testcontainers 9.2.0 → 9.3.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.
Files changed (182) hide show
  1. package/dist/package.json +1 -1
  2. package/dist/src/bound-ports.d.ts +12 -0
  3. package/dist/src/bound-ports.js +50 -0
  4. package/dist/src/clock.d.ts +7 -0
  5. package/dist/src/clock.js +9 -0
  6. package/dist/src/docker/docker-client-config.d.ts +10 -0
  7. package/dist/src/docker/docker-client-config.js +66 -0
  8. package/dist/src/docker/docker-client.d.ts +24 -0
  9. package/dist/src/docker/docker-client.js +198 -0
  10. package/dist/src/docker/functions/container/attach-container.d.ts +3 -0
  11. package/dist/src/docker/functions/container/attach-container.js +25 -0
  12. package/dist/src/docker/functions/container/container-logs.d.ts +6 -0
  13. package/dist/src/docker/functions/container/container-logs.js +32 -0
  14. package/dist/src/docker/functions/container/create-container.d.ts +30 -0
  15. package/dist/src/docker/functions/container/create-container.js +114 -0
  16. package/dist/src/docker/functions/container/exec-container.d.ts +9 -0
  17. package/dist/src/docker/functions/container/exec-container.js +59 -0
  18. package/dist/src/docker/functions/container/get-container.d.ts +3 -0
  19. package/dist/src/docker/functions/container/get-container.js +49 -0
  20. package/dist/src/docker/functions/container/inspect-container.d.ts +19 -0
  21. package/dist/src/docker/functions/container/inspect-container.js +67 -0
  22. package/dist/src/docker/functions/container/list-containers.d.ts +2 -0
  23. package/dist/src/docker/functions/container/list-containers.js +25 -0
  24. package/dist/src/docker/functions/container/put-container-archive.d.ts +9 -0
  25. package/dist/src/docker/functions/container/put-container-archive.js +23 -0
  26. package/dist/src/docker/functions/container/remove-container.d.ts +5 -0
  27. package/dist/src/docker/functions/container/remove-container.js +23 -0
  28. package/dist/src/docker/functions/container/restart-container.d.ts +5 -0
  29. package/dist/src/docker/functions/container/restart-container.js +23 -0
  30. package/dist/src/docker/functions/container/start-container.d.ts +2 -0
  31. package/dist/src/docker/functions/container/start-container.js +23 -0
  32. package/dist/src/docker/functions/container/stop-container.d.ts +5 -0
  33. package/dist/src/docker/functions/container/stop-container.js +29 -0
  34. package/dist/src/docker/functions/create-labels.d.ts +3 -0
  35. package/dist/src/docker/functions/create-labels.js +17 -0
  36. package/dist/src/docker/functions/demux-stream.d.ts +3 -0
  37. package/dist/src/docker/functions/demux-stream.js +32 -0
  38. package/dist/src/docker/functions/get-info.d.ts +11 -0
  39. package/dist/src/docker/functions/get-info.js +38 -0
  40. package/dist/src/docker/functions/image/build-image.d.ts +13 -0
  41. package/dist/src/docker/functions/image/build-image.js +76 -0
  42. package/dist/src/docker/functions/image/image-exists.d.ts +3 -0
  43. package/dist/src/docker/functions/image/image-exists.js +34 -0
  44. package/dist/src/docker/functions/image/list-images.d.ts +3 -0
  45. package/dist/src/docker/functions/image/list-images.js +34 -0
  46. package/dist/src/docker/functions/image/pull-image.d.ts +7 -0
  47. package/dist/src/docker/functions/image/pull-image.js +41 -0
  48. package/dist/src/docker/functions/network/connect-network.d.ts +6 -0
  49. package/dist/src/docker/functions/network/connect-network.js +27 -0
  50. package/dist/src/docker/functions/network/create-network.d.ts +16 -0
  51. package/dist/src/docker/functions/network/create-network.js +38 -0
  52. package/dist/src/docker/functions/network/remove-network.d.ts +1 -0
  53. package/dist/src/docker/functions/network/remove-network.js +30 -0
  54. package/dist/src/docker/functions/run-in-container.d.ts +2 -0
  55. package/dist/src/docker/functions/run-in-container.js +39 -0
  56. package/dist/src/docker/get-remote-docker-unix-socket-path.d.ts +5 -0
  57. package/dist/src/docker/get-remote-docker-unix-socket-path.js +17 -0
  58. package/dist/src/docker/lookup-host-ips.d.ts +5 -0
  59. package/dist/src/docker/lookup-host-ips.js +26 -0
  60. package/dist/src/docker/pull-stream-parser.d.ts +11 -0
  61. package/dist/src/docker/pull-stream-parser.js +63 -0
  62. package/dist/src/docker/rootless-unix-socket-strategy.d.ts +16 -0
  63. package/dist/src/docker/rootless-unix-socket-strategy.js +69 -0
  64. package/dist/src/docker/session-id.d.ts +1 -0
  65. package/dist/src/docker/session-id.js +5 -0
  66. package/dist/src/docker/types.d.ts +79 -0
  67. package/dist/src/docker/types.js +2 -0
  68. package/dist/src/docker-compose/default-docker-compose-options.d.ts +3 -0
  69. package/dist/src/docker-compose/default-docker-compose-options.js +37 -0
  70. package/dist/src/docker-compose/docker-compose-options.d.ts +9 -0
  71. package/dist/src/docker-compose/docker-compose-options.js +2 -0
  72. package/dist/src/docker-compose/functions/container-name-resolver.d.ts +1 -0
  73. package/dist/src/docker-compose/functions/container-name-resolver.js +15 -0
  74. package/dist/src/docker-compose/functions/docker-compose-down.d.ts +3 -0
  75. package/dist/src/docker-compose/functions/docker-compose-down.js +39 -0
  76. package/dist/src/docker-compose/functions/docker-compose-stop.d.ts +2 -0
  77. package/dist/src/docker-compose/functions/docker-compose-stop.js +29 -0
  78. package/dist/src/docker-compose/functions/docker-compose-up.d.ts +2 -0
  79. package/dist/src/docker-compose/functions/docker-compose-up.js +41 -0
  80. package/dist/src/docker-compose-environment/docker-compose-environment.d.ts +25 -0
  81. package/dist/src/docker-compose-environment/docker-compose-environment.js +134 -0
  82. package/dist/src/docker-compose-environment/downed-docker-compose-environment.d.ts +2 -0
  83. package/dist/src/docker-compose-environment/downed-docker-compose-environment.js +6 -0
  84. package/dist/src/docker-compose-environment/started-docker-compose-environment.d.ts +15 -0
  85. package/dist/src/docker-compose-environment/started-docker-compose-environment.js +46 -0
  86. package/dist/src/docker-compose-environment/stopped-docker-compose-environment.d.ts +8 -0
  87. package/dist/src/docker-compose-environment/stopped-docker-compose-environment.js +27 -0
  88. package/dist/src/docker-image-name.d.ts +15 -0
  89. package/dist/src/docker-image-name.js +63 -0
  90. package/dist/src/dockerfile-parser.d.ts +3 -0
  91. package/dist/src/dockerfile-parser.js +39 -0
  92. package/dist/src/generic-container/generic-container-builder.d.ts +18 -0
  93. package/dist/src/generic-container/generic-container-builder.js +98 -0
  94. package/dist/src/generic-container/generic-container.d.ts +77 -0
  95. package/dist/src/generic-container/generic-container.js +312 -0
  96. package/dist/src/generic-container/started-generic-container.d.ts +31 -0
  97. package/dist/src/generic-container/started-generic-container.js +97 -0
  98. package/dist/src/generic-container/stopped-generic-container.d.ts +3 -0
  99. package/dist/src/generic-container/stopped-generic-container.js +6 -0
  100. package/dist/src/hash.d.ts +1 -0
  101. package/dist/src/hash.js +11 -0
  102. package/dist/src/http-wait-strategy.d.ts +27 -0
  103. package/dist/src/http-wait-strategy.js +113 -0
  104. package/dist/src/images.d.ts +2 -0
  105. package/dist/src/images.js +6 -0
  106. package/dist/src/index.d.ts +21 -0
  107. package/dist/src/index.js +54 -0
  108. package/dist/src/labels.d.ts +5 -0
  109. package/dist/src/labels.js +8 -0
  110. package/dist/src/logger.d.ts +36 -0
  111. package/dist/src/logger.js +61 -0
  112. package/dist/src/modules/abstract-started-container.d.ts +21 -0
  113. package/dist/src/modules/abstract-started-container.js +59 -0
  114. package/dist/src/modules/arangodb/arangodb-container.d.ts +19 -0
  115. package/dist/src/modules/arangodb/arangodb-container.js +60 -0
  116. package/dist/src/modules/elasticsearch/elasticsearch-container.d.ts +12 -0
  117. package/dist/src/modules/elasticsearch/elasticsearch-container.js +43 -0
  118. package/dist/src/modules/kafka/kafka-container.d.ts +46 -0
  119. package/dist/src/modules/kafka/kafka-container.js +172 -0
  120. package/dist/src/modules/mongodb/mongodb-container.d.ts +19 -0
  121. package/dist/src/modules/mongodb/mongodb-container.js +85 -0
  122. package/dist/src/modules/mysql/mysql-container.d.ts +29 -0
  123. package/dist/src/modules/mysql/mysql-container.js +102 -0
  124. package/dist/src/modules/nats/nats-container.d.ts +55 -0
  125. package/dist/src/modules/nats/nats-container.js +97 -0
  126. package/dist/src/modules/neo4j/neo4j-container.d.ts +23 -0
  127. package/dist/src/modules/neo4j/neo4j-container.js +82 -0
  128. package/dist/src/modules/postgresql/postgresql-container.d.ts +28 -0
  129. package/dist/src/modules/postgresql/postgresql-container.js +87 -0
  130. package/dist/src/network.d.ts +17 -0
  131. package/dist/src/network.js +54 -0
  132. package/dist/src/port-check.d.ts +17 -0
  133. package/dist/src/port-check.js +84 -0
  134. package/dist/src/port-forwarder.d.ts +17 -0
  135. package/dist/src/port-forwarder.js +81 -0
  136. package/dist/src/port-generator.d.ts +15 -0
  137. package/dist/src/port-generator.js +51 -0
  138. package/dist/src/port.d.ts +10 -0
  139. package/dist/src/port.js +47 -0
  140. package/dist/src/pull-policy.d.ts +9 -0
  141. package/dist/src/pull-policy.js +15 -0
  142. package/dist/src/reaper.d.ts +14 -0
  143. package/dist/src/reaper.js +141 -0
  144. package/dist/src/registry-auth-locator/auths.d.ts +8 -0
  145. package/dist/src/registry-auth-locator/auths.js +56 -0
  146. package/dist/src/registry-auth-locator/cred-helpers.d.ts +6 -0
  147. package/dist/src/registry-auth-locator/cred-helpers.js +15 -0
  148. package/dist/src/registry-auth-locator/credential-provider.d.ts +10 -0
  149. package/dist/src/registry-auth-locator/credential-provider.js +83 -0
  150. package/dist/src/registry-auth-locator/creds-store.d.ts +6 -0
  151. package/dist/src/registry-auth-locator/creds-store.js +15 -0
  152. package/dist/src/registry-auth-locator/get-auth-config.d.ts +2 -0
  153. package/dist/src/registry-auth-locator/get-auth-config.js +65 -0
  154. package/dist/src/registry-auth-locator/registry-auth-locator.d.ts +6 -0
  155. package/dist/src/registry-auth-locator/registry-auth-locator.js +2 -0
  156. package/dist/src/registry-auth-locator/registry-matches.d.ts +1 -0
  157. package/dist/src/registry-auth-locator/registry-matches.js +5 -0
  158. package/dist/src/registry-auth-locator/types.d.ts +23 -0
  159. package/dist/src/registry-auth-locator/types.js +2 -0
  160. package/dist/src/retry-strategy.d.ts +17 -0
  161. package/dist/src/retry-strategy.js +46 -0
  162. package/dist/src/startup-check-strategy.d.ts +7 -0
  163. package/dist/src/startup-check-strategy.js +30 -0
  164. package/dist/src/stream-utils.d.ts +6 -0
  165. package/dist/src/stream-utils.js +46 -0
  166. package/dist/src/system-info.d.ts +17 -0
  167. package/dist/src/system-info.js +51 -0
  168. package/dist/src/test-container.d.ts +66 -0
  169. package/dist/src/test-container.js +2 -0
  170. package/dist/src/test-containers.d.ts +3 -0
  171. package/dist/src/test-containers.js +22 -0
  172. package/dist/src/type-guards.d.ts +1 -0
  173. package/dist/src/type-guards.js +7 -0
  174. package/dist/src/uuid.d.ts +6 -0
  175. package/dist/src/uuid.js +13 -0
  176. package/dist/src/wait-for-container.d.ts +4 -0
  177. package/dist/src/wait-for-container.js +34 -0
  178. package/dist/src/wait-strategy.d.ts +32 -0
  179. package/dist/src/wait-strategy.js +137 -0
  180. package/dist/src/wait.d.ts +7 -0
  181. package/dist/src/wait.js +17 -0
  182. package/package.json +1 -1
package/dist/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "testcontainers",
3
3
  "author": "Cristian Greco",
4
- "version": "9.2.0",
4
+ "version": "9.3.0",
5
5
  "main": "dist/src/index",
6
6
  "types": "dist/src/index",
7
7
  "keywords": [
@@ -0,0 +1,12 @@
1
+ import { PortWithOptionalBinding } from "./port";
2
+ import { InspectResult } from "./docker/functions/container/inspect-container";
3
+ import { HostIps } from "./docker/lookup-host-ips";
4
+ export declare class BoundPorts {
5
+ private readonly ports;
6
+ getBinding(port: number): number;
7
+ getFirstBinding(): number;
8
+ setBinding(key: number, value: number): void;
9
+ iterator(): Iterable<[number, number]>;
10
+ filter(ports: PortWithOptionalBinding[]): BoundPorts;
11
+ static fromInspectResult(hostIps: HostIps, inspectResult: InspectResult): BoundPorts;
12
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BoundPorts = void 0;
4
+ const port_1 = require("./port");
5
+ class BoundPorts {
6
+ constructor() {
7
+ this.ports = new Map();
8
+ }
9
+ getBinding(port) {
10
+ const binding = this.ports.get(port);
11
+ if (!binding) {
12
+ throw new Error(`No port binding found for :${port}`);
13
+ }
14
+ return binding;
15
+ }
16
+ getFirstBinding() {
17
+ const firstBinding = this.ports.values().next().value;
18
+ if (!firstBinding) {
19
+ throw new Error("No port bindings found");
20
+ }
21
+ else {
22
+ return firstBinding;
23
+ }
24
+ }
25
+ setBinding(key, value) {
26
+ this.ports.set(key, value);
27
+ }
28
+ iterator() {
29
+ return this.ports;
30
+ }
31
+ filter(ports) {
32
+ const boundPorts = new BoundPorts();
33
+ const containerPorts = ports.map((port) => (0, port_1.getContainerPort)(port));
34
+ for (const [internalPort, hostPort] of this.iterator()) {
35
+ if (containerPorts.includes(internalPort)) {
36
+ boundPorts.setBinding(internalPort, hostPort);
37
+ }
38
+ }
39
+ return boundPorts;
40
+ }
41
+ static fromInspectResult(hostIps, inspectResult) {
42
+ const boundPorts = new BoundPorts();
43
+ Object.entries(inspectResult.ports).forEach(([containerPort, hostBindings]) => {
44
+ const hostPort = (0, port_1.resolveHostPortBinding)(hostIps, hostBindings);
45
+ boundPorts.setBinding(parseInt(containerPort), hostPort);
46
+ });
47
+ return boundPorts;
48
+ }
49
+ }
50
+ exports.BoundPorts = BoundPorts;
@@ -0,0 +1,7 @@
1
+ export type Time = number;
2
+ export interface Clock {
3
+ getTime(): Time;
4
+ }
5
+ export declare class SystemClock implements Clock {
6
+ getTime(): Time;
7
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SystemClock = void 0;
4
+ class SystemClock {
5
+ getTime() {
6
+ return Date.now();
7
+ }
8
+ }
9
+ exports.SystemClock = SystemClock;
@@ -0,0 +1,10 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ /// <reference types="node" />
4
+ /// <reference types="node" />
5
+ export type DockerClientConfig = {
6
+ dockerHost?: string;
7
+ dockerTlsVerify?: string;
8
+ dockerCertPath?: string;
9
+ };
10
+ export declare const getDockerClientConfig: (env?: NodeJS.ProcessEnv) => Promise<DockerClientConfig>;
@@ -0,0 +1,66 @@
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.getDockerClientConfig = void 0;
16
+ const path_1 = __importDefault(require("path"));
17
+ const logger_1 = require("../logger");
18
+ const os_1 = require("os");
19
+ const fs_1 = require("fs");
20
+ const promises_1 = require("fs/promises");
21
+ const properties_reader_1 = __importDefault(require("properties-reader"));
22
+ const getDockerClientConfig = (env = process.env) => __awaiter(void 0, void 0, void 0, function* () {
23
+ let dockerHost;
24
+ let dockerTlsVerify;
25
+ let dockerCertPath;
26
+ const file = path_1.default.resolve((0, os_1.homedir)(), ".testcontainers.properties");
27
+ if ((0, fs_1.existsSync)(file)) {
28
+ logger_1.log.debug("Found .testcontainers.properties file");
29
+ const string = yield (0, promises_1.readFile)(file, { encoding: "utf-8" });
30
+ const properties = (0, properties_reader_1.default)("").read(string);
31
+ const host = properties.get("docker.host");
32
+ if (host !== null) {
33
+ dockerHost = host;
34
+ }
35
+ const tlsVerify = properties.get("docker.tls.verify");
36
+ if (tlsVerify !== null) {
37
+ dockerTlsVerify = `${tlsVerify}`;
38
+ }
39
+ const certPath = properties.get("docker.cert.path");
40
+ if (certPath !== null) {
41
+ dockerCertPath = certPath;
42
+ }
43
+ }
44
+ if (env["DOCKER_HOST"] !== undefined) {
45
+ dockerHost = env["DOCKER_HOST"];
46
+ }
47
+ if (env["DOCKER_TLS_VERIFY"] !== undefined) {
48
+ dockerTlsVerify = env["DOCKER_TLS_VERIFY"];
49
+ }
50
+ if (env["DOCKER_CERT_PATH"] !== undefined) {
51
+ dockerCertPath = env["DOCKER_CERT_PATH"];
52
+ }
53
+ let logStr = "Loaded properties: ";
54
+ if (dockerHost !== undefined) {
55
+ logStr += `dockerHost=${dockerHost}, `;
56
+ }
57
+ if (dockerTlsVerify !== undefined) {
58
+ logStr += `dockerTlsVerify=${dockerTlsVerify}, `;
59
+ }
60
+ if (dockerCertPath !== undefined) {
61
+ logStr += `dockerCertPath=${dockerCertPath}`;
62
+ }
63
+ logger_1.log.debug(logStr);
64
+ return { dockerHost, dockerTlsVerify, dockerCertPath };
65
+ });
66
+ exports.getDockerClientConfig = getDockerClientConfig;
@@ -0,0 +1,24 @@
1
+ /// <reference types="node" />
2
+ import Dockerode from "dockerode";
3
+ import { HostIps } from "./lookup-host-ips";
4
+ type DockerClient = {
5
+ uri: string;
6
+ host: string;
7
+ hostIps: HostIps;
8
+ dockerode: Dockerode;
9
+ indexServerAddress: string;
10
+ composeEnvironment: NodeJS.ProcessEnv;
11
+ };
12
+ export type DockerClientInit = {
13
+ uri: string;
14
+ dockerode: Dockerode;
15
+ composeEnvironment: NodeJS.ProcessEnv;
16
+ };
17
+ export interface DockerClientStrategy {
18
+ init?(): Promise<void>;
19
+ isApplicable(): boolean;
20
+ getDockerClient(): Promise<DockerClientInit>;
21
+ getName(): string;
22
+ }
23
+ export declare const dockerClient: () => Promise<DockerClient>;
24
+ export {};
@@ -0,0 +1,198 @@
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 = require("fs");
21
+ const run_in_container_1 = require("./functions/run-in-container");
22
+ const session_id_1 = require("./session-id");
23
+ const lookup_host_ips_1 = require("./lookup-host-ips");
24
+ const system_info_1 = require("../system-info");
25
+ const rootless_unix_socket_strategy_1 = require("./rootless-unix-socket-strategy");
26
+ const stream_utils_1 = require("../stream-utils");
27
+ const stream_1 = require("stream");
28
+ const docker_client_config_1 = require("./docker-client-config");
29
+ const getDockerClient = () => __awaiter(void 0, void 0, void 0, function* () {
30
+ const strategies = [
31
+ new ConfigurationStrategy(),
32
+ new UnixSocketStrategy(),
33
+ new rootless_unix_socket_strategy_1.RootlessUnixSocketStrategy(),
34
+ new NpipeSocketStrategy(),
35
+ ];
36
+ for (const strategy of strategies) {
37
+ if (strategy.init) {
38
+ yield strategy.init();
39
+ }
40
+ if (strategy.isApplicable()) {
41
+ logger_1.log.debug(`Found applicable Docker client strategy: ${strategy.getName()}`);
42
+ const { uri, dockerode, composeEnvironment } = yield strategy.getDockerClient();
43
+ logger_1.log.debug(`Testing Docker client strategy URI: ${uri}`);
44
+ if (yield isDockerDaemonReachable(dockerode)) {
45
+ const indexServerAddress = (yield (0, system_info_1.getSystemInfo)(dockerode)).dockerInfo.indexServerAddress;
46
+ const host = yield resolveHost(dockerode, indexServerAddress, uri);
47
+ const hostIps = yield (0, lookup_host_ips_1.lookupHostIps)(host);
48
+ logger_1.log.info(`Using Docker client strategy: ${strategy.getName()}, Docker host: ${host} (${hostIps
49
+ .map((hostIp) => hostIp.address)
50
+ .join(", ")})`);
51
+ return { uri, host, hostIps, dockerode, indexServerAddress, composeEnvironment };
52
+ }
53
+ else {
54
+ logger_1.log.warn(`Docker client strategy ${strategy.getName()} is not reachable`);
55
+ }
56
+ }
57
+ }
58
+ throw new Error("No Docker client strategy found");
59
+ });
60
+ const isDockerDaemonReachable = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
61
+ try {
62
+ const response = yield dockerode.ping();
63
+ return (yield (0, stream_utils_1.streamToString)(stream_1.Readable.from(response))) === "OK";
64
+ }
65
+ catch (err) {
66
+ logger_1.log.warn(`Docker daemon is not reachable: ${err}`);
67
+ return false;
68
+ }
69
+ });
70
+ class ConfigurationStrategy {
71
+ init() {
72
+ return __awaiter(this, void 0, void 0, function* () {
73
+ this.dockerConfig = yield (0, docker_client_config_1.getDockerClientConfig)();
74
+ });
75
+ }
76
+ getDockerClient() {
77
+ return __awaiter(this, void 0, void 0, function* () {
78
+ const { dockerHost, dockerTlsVerify, dockerCertPath } = this.dockerConfig;
79
+ const dockerOptions = { headers: { "x-tc-sid": session_id_1.sessionId } };
80
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
81
+ const { pathname, hostname, port } = new url_1.URL(dockerHost);
82
+ if (hostname !== "") {
83
+ dockerOptions.host = hostname;
84
+ dockerOptions.port = port;
85
+ }
86
+ else {
87
+ dockerOptions.socketPath = pathname;
88
+ }
89
+ if (dockerTlsVerify === "1" && dockerCertPath !== undefined) {
90
+ dockerOptions.ca = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "ca.pem"));
91
+ dockerOptions.cert = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "cert.pem"));
92
+ dockerOptions.key = yield fs_1.promises.readFile(path_1.default.resolve(dockerCertPath, "key.pem"));
93
+ }
94
+ return {
95
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
96
+ uri: dockerHost,
97
+ dockerode: new dockerode_1.default(dockerOptions),
98
+ composeEnvironment: {
99
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
100
+ DOCKER_HOST: dockerHost,
101
+ DOCKER_TLS_VERIFY: dockerTlsVerify,
102
+ DOCKER_CERT_PATH: dockerCertPath,
103
+ },
104
+ };
105
+ });
106
+ }
107
+ isApplicable() {
108
+ return this.dockerConfig.dockerHost !== undefined;
109
+ }
110
+ getName() {
111
+ return "ConfigurationStrategy";
112
+ }
113
+ }
114
+ class UnixSocketStrategy {
115
+ getDockerClient() {
116
+ return __awaiter(this, void 0, void 0, function* () {
117
+ return {
118
+ uri: "unix:///var/run/docker.sock",
119
+ dockerode: new dockerode_1.default({ socketPath: "/var/run/docker.sock" }),
120
+ composeEnvironment: {},
121
+ };
122
+ });
123
+ }
124
+ isApplicable() {
125
+ return (process.platform === "linux" || process.platform === "darwin") && (0, fs_1.existsSync)("/var/run/docker.sock");
126
+ }
127
+ getName() {
128
+ return "UnixSocketStrategy";
129
+ }
130
+ }
131
+ class NpipeSocketStrategy {
132
+ getDockerClient() {
133
+ return __awaiter(this, void 0, void 0, function* () {
134
+ return {
135
+ uri: "npipe:////./pipe/docker_engine",
136
+ dockerode: new dockerode_1.default({ socketPath: "//./pipe/docker_engine" }),
137
+ composeEnvironment: {},
138
+ };
139
+ });
140
+ }
141
+ isApplicable() {
142
+ return process.platform === "win32";
143
+ }
144
+ getName() {
145
+ return "NpipeSocketStrategy";
146
+ }
147
+ }
148
+ const resolveHost = (dockerode, indexServerAddress, uri) => __awaiter(void 0, void 0, void 0, function* () {
149
+ if (process.env.TESTCONTAINERS_HOST_OVERRIDE !== undefined) {
150
+ return process.env.TESTCONTAINERS_HOST_OVERRIDE;
151
+ }
152
+ const { protocol, hostname } = new url_1.URL(uri);
153
+ switch (protocol) {
154
+ case "http:":
155
+ case "https:":
156
+ case "tcp:":
157
+ return hostname;
158
+ case "unix:":
159
+ case "npipe:": {
160
+ if (isInContainer()) {
161
+ const gateway = yield findGateway(dockerode);
162
+ if (gateway !== undefined) {
163
+ return gateway;
164
+ }
165
+ const defaultGateway = yield findDefaultGateway(dockerode, indexServerAddress);
166
+ if (defaultGateway !== undefined) {
167
+ return defaultGateway;
168
+ }
169
+ }
170
+ return "localhost";
171
+ }
172
+ default:
173
+ throw new Error(`Unsupported protocol: ${protocol}`);
174
+ }
175
+ });
176
+ const findGateway = (dockerode) => __awaiter(void 0, void 0, void 0, function* () {
177
+ var _a, _b, _c;
178
+ logger_1.log.debug(`Checking gateway for Docker host`);
179
+ const inspectResult = yield dockerode.getNetwork("bridge").inspect();
180
+ 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;
181
+ });
182
+ const findDefaultGateway = (dockerode, indexServerAddress) => __awaiter(void 0, void 0, void 0, function* () {
183
+ logger_1.log.debug(`Checking default gateway for Docker host`);
184
+ return (0, run_in_container_1.runInContainer)(dockerode, indexServerAddress, "alpine:3.14", [
185
+ "sh",
186
+ "-c",
187
+ "ip route|awk '/default/ { print $3 }'",
188
+ ]);
189
+ });
190
+ const isInContainer = () => (0, fs_1.existsSync)("/.dockerenv");
191
+ let _dockerClient;
192
+ const dockerClient = () => {
193
+ if (!_dockerClient) {
194
+ _dockerClient = getDockerClient();
195
+ }
196
+ return _dockerClient;
197
+ };
198
+ exports.dockerClient = dockerClient;
@@ -0,0 +1,3 @@
1
+ import { Readable } from "stream";
2
+ import Dockerode from "dockerode";
3
+ export declare const attachContainer: (dockerode: Dockerode, container: Dockerode.Container) => Promise<Readable>;
@@ -0,0 +1,25 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.attachContainer = void 0;
13
+ const demux_stream_1 = require("../demux-stream");
14
+ const logger_1 = require("../../../logger");
15
+ const attachContainer = (dockerode, container) => __awaiter(void 0, void 0, void 0, function* () {
16
+ try {
17
+ const stream = (yield container.attach({ stream: true, stdout: true, stderr: true }));
18
+ return (0, demux_stream_1.demuxStream)(dockerode, stream);
19
+ }
20
+ catch (err) {
21
+ logger_1.log.error(`Failed to attach to container ${container.id}: ${err}`);
22
+ throw err;
23
+ }
24
+ });
25
+ exports.attachContainer = attachContainer;
@@ -0,0 +1,6 @@
1
+ import Dockerode from "dockerode";
2
+ import { Readable } from "stream";
3
+ export type ContainerLogsOptions = {
4
+ since?: Date;
5
+ };
6
+ export declare const containerLogs: (container: Dockerode.Container, options?: ContainerLogsOptions) => Promise<Readable>;
@@ -0,0 +1,32 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.containerLogs = void 0;
13
+ const logger_1 = require("../../../logger");
14
+ const demux_stream_1 = require("../demux-stream");
15
+ const docker_client_1 = require("../../docker-client");
16
+ const containerLogs = (container, options = {}) => __awaiter(void 0, void 0, void 0, function* () {
17
+ try {
18
+ const stream = (yield container.logs({
19
+ follow: true,
20
+ stdout: true,
21
+ stderr: true,
22
+ since: options.since ? options.since.getTime() / 1000 : 0,
23
+ }));
24
+ stream.socket.unref();
25
+ return (0, demux_stream_1.demuxStream)((yield (0, docker_client_1.dockerClient)()).dockerode, stream);
26
+ }
27
+ catch (err) {
28
+ logger_1.log.error(`Failed to get container logs: ${err}`);
29
+ throw err;
30
+ }
31
+ });
32
+ exports.containerLogs = containerLogs;
@@ -0,0 +1,30 @@
1
+ import { DockerImageName } from "../../../docker-image-name";
2
+ import Dockerode from "dockerode";
3
+ import { PortWithOptionalBinding } from "../../../port";
4
+ import { BindMount, Environment, ExtraHost, HealthCheck, Labels, ResourcesQuota, TmpFs, Ulimits } from "../../types";
5
+ export type CreateContainerOptions = {
6
+ imageName: DockerImageName;
7
+ environment: Environment;
8
+ command: string[];
9
+ entrypoint?: string[];
10
+ bindMounts: BindMount[];
11
+ tmpFs: TmpFs;
12
+ exposedPorts: PortWithOptionalBinding[];
13
+ name?: string;
14
+ reusable: boolean;
15
+ labels?: Labels;
16
+ networkMode?: string;
17
+ healthCheck?: HealthCheck;
18
+ useDefaultLogDriver: boolean;
19
+ privilegedMode: boolean;
20
+ autoRemove: boolean;
21
+ extraHosts: ExtraHost[];
22
+ ipcMode?: string;
23
+ ulimits?: Ulimits;
24
+ addedCapabilities?: string[];
25
+ droppedCapabilities?: string[];
26
+ user?: string;
27
+ workingDir?: string;
28
+ resourcesQuota?: ResourcesQuota;
29
+ };
30
+ export declare const createContainer: (options: CreateContainerOptions) => Promise<Dockerode.Container>;
@@ -0,0 +1,114 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createContainer = void 0;
13
+ const logger_1 = require("../../../logger");
14
+ const docker_client_1 = require("../../docker-client");
15
+ const port_1 = require("../../../port");
16
+ const create_labels_1 = require("../create-labels");
17
+ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function* () {
18
+ var _a, _b;
19
+ try {
20
+ logger_1.log.info(`Creating container for image: ${options.imageName}`);
21
+ const { dockerode } = yield (0, docker_client_1.dockerClient)();
22
+ return yield dockerode.createContainer({
23
+ name: options.name,
24
+ User: options.user,
25
+ Image: options.imageName.toString(),
26
+ Env: getEnvironment(options.environment),
27
+ ExposedPorts: getExposedPorts(options.exposedPorts),
28
+ Cmd: options.command,
29
+ Entrypoint: options.entrypoint,
30
+ Labels: (0, create_labels_1.createLabels)(options.reusable, options.imageName, options.labels),
31
+ Healthcheck: getHealthCheck(options.healthCheck),
32
+ WorkingDir: options.workingDir,
33
+ HostConfig: {
34
+ IpcMode: options.ipcMode,
35
+ ExtraHosts: getExtraHosts(options.extraHosts),
36
+ AutoRemove: options.autoRemove,
37
+ NetworkMode: options.networkMode,
38
+ PortBindings: getPortBindings(options.exposedPorts),
39
+ Binds: getBindMounts(options.bindMounts),
40
+ Tmpfs: options.tmpFs,
41
+ LogConfig: getLogConfig(options.useDefaultLogDriver),
42
+ Privileged: options.privilegedMode,
43
+ Ulimits: getUlimits(options.ulimits),
44
+ CapAdd: options.addedCapabilities,
45
+ CapDrop: options.droppedCapabilities,
46
+ Memory: (_a = options.resourcesQuota) === null || _a === void 0 ? void 0 : _a.memory,
47
+ NanoCpus: (_b = options.resourcesQuota) === null || _b === void 0 ? void 0 : _b.cpu,
48
+ },
49
+ });
50
+ }
51
+ catch (err) {
52
+ logger_1.log.error(`Failed to create container for image ${options.imageName}: ${err}`);
53
+ throw err;
54
+ }
55
+ });
56
+ exports.createContainer = createContainer;
57
+ const getEnvironment = (environment) => Object.entries(environment).reduce((dockerodeEnvironment, [key, value]) => [...dockerodeEnvironment, `${key}=${value}`], []);
58
+ const getExposedPorts = (exposedPorts) => {
59
+ const dockerodeExposedPorts = {};
60
+ for (const exposedPort of exposedPorts) {
61
+ dockerodeExposedPorts[(0, port_1.getContainerPort)(exposedPort).toString()] = {};
62
+ }
63
+ return dockerodeExposedPorts;
64
+ };
65
+ const getExtraHosts = (extraHosts) => {
66
+ return extraHosts.map((extraHost) => `${extraHost.host}:${extraHost.ipAddress}`);
67
+ };
68
+ const getPortBindings = (exposedPorts) => {
69
+ const dockerodePortBindings = {};
70
+ for (const exposedPort of exposedPorts) {
71
+ if ((0, port_1.hasHostBinding)(exposedPort)) {
72
+ dockerodePortBindings[exposedPort.container] = [{ HostPort: exposedPort.host.toString() }];
73
+ }
74
+ else {
75
+ dockerodePortBindings[exposedPort] = [{ HostPort: "0" }];
76
+ }
77
+ }
78
+ return dockerodePortBindings;
79
+ };
80
+ const getBindMounts = (bindMounts) => {
81
+ return bindMounts.map(({ source, target, mode }) => `${source}:${target}:${mode}`);
82
+ };
83
+ const getHealthCheck = (healthCheck) => {
84
+ if (healthCheck === undefined) {
85
+ return undefined;
86
+ }
87
+ return {
88
+ Test: healthCheck.test,
89
+ Interval: healthCheck.interval ? toNanos(healthCheck.interval) : 0,
90
+ Timeout: healthCheck.timeout ? toNanos(healthCheck.timeout) : 0,
91
+ Retries: healthCheck.retries || 0,
92
+ StartPeriod: healthCheck.startPeriod ? toNanos(healthCheck.startPeriod) : 0,
93
+ };
94
+ };
95
+ const toNanos = (duration) => duration * 1e6;
96
+ const getLogConfig = (useDefaultLogDriver) => {
97
+ if (!useDefaultLogDriver) {
98
+ return undefined;
99
+ }
100
+ return {
101
+ Type: "json-file",
102
+ Config: {},
103
+ };
104
+ };
105
+ const getUlimits = (ulimits) => {
106
+ if (!ulimits) {
107
+ return undefined;
108
+ }
109
+ return Object.entries(ulimits).map(([key, value]) => ({
110
+ Name: key,
111
+ Hard: value.hard,
112
+ Soft: value.soft,
113
+ }));
114
+ };
@@ -0,0 +1,9 @@
1
+ import { ExecResult } from "../../types";
2
+ import Dockerode from "dockerode";
3
+ type ExecContainerOptions = {
4
+ tty: boolean;
5
+ stdin: boolean;
6
+ detach: boolean;
7
+ };
8
+ export declare const execContainer: (container: Dockerode.Container, command: string[], options: ExecContainerOptions, shouldLog?: boolean) => Promise<ExecResult>;
9
+ export {};