testcontainers 9.6.0 → 9.8.0-beta.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.
- package/dist/package.json +12 -12
- package/dist/src/docker/{docker-client-config.d.ts → client/docker-client-config.d.ts} +1 -0
- package/dist/src/docker/client/docker-client-config.js +79 -0
- package/dist/src/docker/client/docker-client.d.ts +18 -0
- package/dist/src/docker/client/docker-client.js +90 -0
- package/dist/src/docker/client/strategy/configuration-strategy.d.ts +11 -0
- package/dist/src/docker/client/strategy/configuration-strategy.js +68 -0
- package/dist/src/docker/client/strategy/docker-client-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/docker-client-strategy.js +2 -0
- package/dist/src/docker/client/strategy/npipe-socket-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/npipe-socket-strategy.js +35 -0
- package/dist/src/docker/{rootless-unix-socket-strategy.d.ts → client/strategy/rootless-unix-socket-strategy.d.ts} +3 -2
- package/dist/src/docker/{rootless-unix-socket-strategy.js → client/strategy/rootless-unix-socket-strategy.js} +2 -1
- package/dist/src/docker/client/strategy/testcontainers-host-strategy.d.ts +9 -0
- package/dist/src/docker/client/strategy/testcontainers-host-strategy.js +52 -0
- package/dist/src/docker/client/strategy/unix-socket-strategy.d.ts +7 -0
- package/dist/src/docker/client/strategy/unix-socket-strategy.js +36 -0
- package/dist/src/docker/functions/container/attach-container.js +1 -1
- package/dist/src/docker/functions/container/container-logs.js +2 -2
- package/dist/src/docker/functions/container/create-container.js +8 -6
- package/dist/src/docker/functions/container/exec-container.d.ts +2 -3
- package/dist/src/docker/functions/container/exec-container.js +9 -7
- package/dist/src/docker/functions/container/get-container.js +4 -4
- package/dist/src/docker/functions/container/inspect-container.js +1 -1
- package/dist/src/docker/functions/container/list-containers.js +2 -2
- package/dist/src/docker/functions/container/put-container-archive.js +1 -1
- package/dist/src/docker/functions/container/remove-container.js +1 -1
- package/dist/src/docker/functions/container/restart-container.js +1 -1
- package/dist/src/docker/functions/container/start-container.js +1 -1
- package/dist/src/docker/functions/container/stop-container.js +2 -2
- package/dist/src/docker/functions/create-labels.js +0 -3
- package/dist/src/docker/functions/image/build-image.js +10 -5
- package/dist/src/docker/functions/image/pull-image.js +11 -4
- package/dist/src/docker/functions/network/connect-network.js +5 -4
- package/dist/src/docker/functions/network/create-network.js +4 -3
- package/dist/src/docker/functions/network/remove-network.js +5 -4
- package/dist/src/docker/functions/run-in-container.js +6 -6
- package/dist/src/docker/remote-docker-unix-socket-path.d.ts +6 -0
- package/dist/src/docker/remote-docker-unix-socket-path.js +22 -0
- package/dist/src/docker/resolve-host.d.ts +2 -2
- package/dist/src/docker/resolve-host.js +8 -6
- package/dist/src/docker/types.d.ts +1 -0
- package/dist/src/docker-compose/default-docker-compose-options.js +6 -4
- package/dist/src/docker-compose/docker-compose-options.d.ts +2 -0
- package/dist/src/docker-compose/functions/docker-compose-down.js +1 -1
- package/dist/src/docker-compose/functions/docker-compose-pull.js +4 -4
- package/dist/src/docker-compose/functions/docker-compose-stop.js +1 -1
- package/dist/src/docker-compose/functions/docker-compose-up.js +1 -1
- package/dist/src/docker-compose-environment/docker-compose-environment.js +5 -8
- package/dist/src/generic-container/generic-container-builder.js +4 -4
- package/dist/src/generic-container/generic-container.d.ts +4 -0
- package/dist/src/generic-container/generic-container.js +23 -12
- package/dist/src/generic-container/started-generic-container.js +13 -8
- package/dist/src/images.js +1 -1
- package/dist/src/logger.d.ts +20 -31
- package/dist/src/logger.js +32 -42
- package/dist/src/modules/nats/nats-container.js +1 -1
- package/dist/src/network.js +6 -3
- package/dist/src/port-check.d.ts +3 -3
- package/dist/src/port-check.js +9 -5
- package/dist/src/port-forwarder.js +7 -5
- package/dist/src/reaper.js +16 -10
- package/dist/src/registry-auth-locator/credential-provider.js +3 -5
- package/dist/src/registry-auth-locator/get-auth-config.js +3 -3
- package/dist/src/system-info.js +2 -5
- package/dist/src/test-container.d.ts +1 -0
- package/dist/src/uuid.js +1 -1
- package/dist/src/wait-for-container.js +4 -4
- package/dist/src/wait-strategy/composite-wait-strategy.js +4 -4
- package/dist/src/wait-strategy/health-check-wait-strategy.js +8 -5
- package/dist/src/wait-strategy/host-port-wait-strategy.js +11 -11
- package/dist/src/wait-strategy/http-wait-strategy.js +9 -7
- package/dist/src/wait-strategy/log-wait-strategy.js +7 -7
- package/dist/src/wait-strategy/shell-wait-strategy.js +8 -8
- package/dist/src/wait-strategy/startup-check-strategy.js +8 -5
- package/dist/src/wait-strategy/wait-strategy.d.ts +6 -4
- package/dist/src/wait-strategy/wait-strategy.js +9 -2
- package/package.json +12 -12
- package/dist/src/docker/docker-client-config.js +0 -66
- package/dist/src/docker/docker-client.d.ts +0 -26
- package/dist/src/docker/docker-client.js +0 -156
- package/dist/src/docker/get-remote-docker-unix-socket-path.d.ts +0 -5
- package/dist/src/docker/get-remote-docker-unix-socket-path.js +0 -17
- package/dist/src/docker/pull-stream-parser.d.ts +0 -10
- package/dist/src/docker/pull-stream-parser.js +0 -20
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import archiver from "archiver";
|
|
2
3
|
import { BoundPorts } from "../bound-ports";
|
|
3
4
|
import { PortWithOptionalBinding } from "../port";
|
|
@@ -9,6 +10,7 @@ import { CreateContainerOptions } from "../docker/functions/container/create-con
|
|
|
9
10
|
import { InspectResult } from "../docker/functions/container/inspect-container";
|
|
10
11
|
import { GenericContainerBuilder } from "./generic-container-builder";
|
|
11
12
|
import { StartedNetwork } from "../network";
|
|
13
|
+
import { Readable } from "stream";
|
|
12
14
|
export declare class GenericContainer implements TestContainer {
|
|
13
15
|
readonly image: string;
|
|
14
16
|
static fromDockerfile(context: string, dockerfileName?: string): GenericContainerBuilder;
|
|
@@ -19,6 +21,7 @@ export declare class GenericContainer implements TestContainer {
|
|
|
19
21
|
protected networkMode?: string;
|
|
20
22
|
protected networkAliases: string[];
|
|
21
23
|
protected pullPolicy: PullPolicy;
|
|
24
|
+
protected logConsumer?: (stream: Readable) => unknown;
|
|
22
25
|
constructor(image: string);
|
|
23
26
|
/**
|
|
24
27
|
* @deprecated Since version 9.4.0. Will be removed in version 10.0.0. Use `beforeContainerStarted` instead.
|
|
@@ -65,4 +68,5 @@ export declare class GenericContainer implements TestContainer {
|
|
|
65
68
|
protected getTarToCopy(): archiver.Archiver;
|
|
66
69
|
withWorkingDir(workingDir: string): this;
|
|
67
70
|
withResourcesQuota({ memory, cpu }: ResourcesQuota): this;
|
|
71
|
+
withLogConsumer(logConsumer: (stream: Readable) => unknown): this;
|
|
68
72
|
}
|
|
@@ -24,7 +24,7 @@ const port_forwarder_1 = require("../port-forwarder");
|
|
|
24
24
|
const pull_image_1 = require("../docker/functions/image/pull-image");
|
|
25
25
|
const create_container_1 = require("../docker/functions/container/create-container");
|
|
26
26
|
const connect_network_1 = require("../docker/functions/network/connect-network");
|
|
27
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
27
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
28
28
|
const inspect_container_1 = require("../docker/functions/container/inspect-container");
|
|
29
29
|
const start_container_1 = require("../docker/functions/container/start-container");
|
|
30
30
|
const container_logs_1 = require("../docker/functions/container/container-logs");
|
|
@@ -52,8 +52,8 @@ class GenericContainer {
|
|
|
52
52
|
}
|
|
53
53
|
start() {
|
|
54
54
|
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
-
const { dockerode,
|
|
56
|
-
yield (0, pull_image_1.pullImage)(dockerode, indexServerAddress, {
|
|
55
|
+
const { dockerode, info } = yield (0, docker_client_1.getDockerClient)();
|
|
56
|
+
yield (0, pull_image_1.pullImage)(dockerode, info.dockerInfo.indexServerAddress, {
|
|
57
57
|
imageName: this.opts.imageName,
|
|
58
58
|
force: this.pullPolicy.shouldPull(),
|
|
59
59
|
});
|
|
@@ -79,14 +79,14 @@ class GenericContainer {
|
|
|
79
79
|
if (this.opts.reusable) {
|
|
80
80
|
const containerHash = (0, hash_1.hash)(JSON.stringify(this.opts));
|
|
81
81
|
this.opts.labels = Object.assign(Object.assign({}, this.opts.labels), { [labels_1.LABEL_TESTCONTAINERS_CONTAINER_HASH]: containerHash });
|
|
82
|
-
logger_1.log.debug(`Container reuse has been enabled
|
|
82
|
+
logger_1.log.debug(`Container reuse has been enabled with hash "${containerHash}"`);
|
|
83
83
|
// We might have several async processes try to create a reusable container
|
|
84
84
|
// at once, to avoid possibly creating too many of these, use a lock
|
|
85
85
|
// on the containerHash, this ensures that only single reusable instance is created
|
|
86
86
|
return reusableContainerCreationLock.acquire(containerHash, () => __awaiter(this, void 0, void 0, function* () {
|
|
87
87
|
const container = yield (0, get_container_1.getContainerByHash)(containerHash);
|
|
88
88
|
if (container !== undefined) {
|
|
89
|
-
logger_1.log.debug(`Found container to reuse with hash
|
|
89
|
+
logger_1.log.debug(`Found container to reuse with hash "${containerHash}"`, { containerId: container.id });
|
|
90
90
|
return this.reuseContainer(container);
|
|
91
91
|
}
|
|
92
92
|
else {
|
|
@@ -102,7 +102,7 @@ class GenericContainer {
|
|
|
102
102
|
}
|
|
103
103
|
reuseContainer(container) {
|
|
104
104
|
return __awaiter(this, void 0, void 0, function* () {
|
|
105
|
-
const { host, hostIps } = yield (0, docker_client_1.
|
|
105
|
+
const { host, hostIps } = yield (0, docker_client_1.getDockerClient)();
|
|
106
106
|
const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
|
|
107
107
|
const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
|
|
108
108
|
if (this.startupTimeout !== undefined) {
|
|
@@ -148,21 +148,28 @@ class GenericContainer {
|
|
|
148
148
|
this.tarToCopy.finalize();
|
|
149
149
|
yield (0, put_container_archive_1.putContainerArchive)({ container, stream: this.tarToCopy, containerPath: "/" });
|
|
150
150
|
}
|
|
151
|
-
logger_1.log.info(`Starting container ${this.opts.imageName}
|
|
151
|
+
logger_1.log.info(`Starting container for image "${this.opts.imageName}"...`, { containerId: container.id });
|
|
152
152
|
if (this.containerCreated) {
|
|
153
153
|
yield this.containerCreated(container.id);
|
|
154
154
|
}
|
|
155
155
|
yield (0, start_container_1.startContainer)(container);
|
|
156
|
-
|
|
156
|
+
logger_1.log.info(`Started container for image "${this.opts.imageName}"`, { containerId: container.id });
|
|
157
|
+
const { host, hostIps } = yield (0, docker_client_1.getDockerClient)();
|
|
157
158
|
const inspectResult = yield (0, inspect_container_1.inspectContainer)(container);
|
|
158
159
|
const boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, inspectResult).filter(this.opts.exposedPorts);
|
|
159
160
|
if (this.startupTimeout !== undefined) {
|
|
160
161
|
this.waitStrategy.withStartupTimeout(this.startupTimeout);
|
|
161
162
|
}
|
|
162
|
-
if (logger_1.containerLog.enabled()) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
.
|
|
163
|
+
if (logger_1.containerLog.enabled() || this.logConsumer !== undefined) {
|
|
164
|
+
const logStream = yield (0, container_logs_1.containerLogs)(container);
|
|
165
|
+
if (this.logConsumer !== undefined) {
|
|
166
|
+
this.logConsumer(logStream);
|
|
167
|
+
}
|
|
168
|
+
if (logger_1.containerLog.enabled()) {
|
|
169
|
+
logStream
|
|
170
|
+
.on("data", (data) => logger_1.containerLog.trace(data.trim(), { containerId: container.id }))
|
|
171
|
+
.on("err", (data) => logger_1.containerLog.error(data.trim(), { containerId: container.id }));
|
|
172
|
+
}
|
|
166
173
|
}
|
|
167
174
|
if (this.containerStarting) {
|
|
168
175
|
yield this.containerStarting(inspectResult, false);
|
|
@@ -307,5 +314,9 @@ class GenericContainer {
|
|
|
307
314
|
this.opts.resourcesQuota = { memory: ram, cpu: cpuQuota };
|
|
308
315
|
return this;
|
|
309
316
|
}
|
|
317
|
+
withLogConsumer(logConsumer) {
|
|
318
|
+
this.logConsumer = logConsumer;
|
|
319
|
+
return this;
|
|
320
|
+
}
|
|
310
321
|
}
|
|
311
322
|
exports.GenericContainer = GenericContainer;
|
|
@@ -23,7 +23,7 @@ const stopped_generic_container_1 = require("./stopped-generic-container");
|
|
|
23
23
|
const stop_container_1 = require("../docker/functions/container/stop-container");
|
|
24
24
|
const restart_container_1 = require("../docker/functions/container/restart-container");
|
|
25
25
|
const wait_for_container_1 = require("../wait-for-container");
|
|
26
|
-
const docker_client_1 = require("../docker/docker-client");
|
|
26
|
+
const docker_client_1 = require("../docker/client/docker-client");
|
|
27
27
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
28
28
|
class StartedGenericContainer {
|
|
29
29
|
constructor(container, host, inspectResult, boundPorts, name, waitStrategy) {
|
|
@@ -49,29 +49,31 @@ class StartedGenericContainer {
|
|
|
49
49
|
restart(options = {}) {
|
|
50
50
|
return __awaiter(this, void 0, void 0, function* () {
|
|
51
51
|
const resolvedOptions = Object.assign({ timeout: 0 }, options);
|
|
52
|
-
logger_1.log.info(`Restarting container
|
|
52
|
+
logger_1.log.info(`Restarting container...`, { containerId: this.container.id });
|
|
53
53
|
yield (0, restart_container_1.restartContainer)(this.container, resolvedOptions);
|
|
54
|
-
const { hostIps } = yield (0, docker_client_1.
|
|
54
|
+
const { hostIps } = yield (0, docker_client_1.getDockerClient)();
|
|
55
55
|
this.inspectResult = yield (0, inspect_container_1.inspectContainer)(this.container);
|
|
56
56
|
const startTime = this.inspectResult.state.startedAt;
|
|
57
57
|
if (logger_1.containerLog.enabled()) {
|
|
58
58
|
(yield (0, container_logs_1.containerLogs)(this.container, { since: startTime }))
|
|
59
|
-
.on("data", (data) => logger_1.containerLog.trace(
|
|
60
|
-
.on("err", (data) => logger_1.containerLog.error(
|
|
59
|
+
.on("data", (data) => logger_1.containerLog.trace(data.trim(), { containerId: this.container.id }))
|
|
60
|
+
.on("err", (data) => logger_1.containerLog.error(data.trim(), { containerId: this.container.id }));
|
|
61
61
|
}
|
|
62
62
|
this.boundPorts = bound_ports_1.BoundPorts.fromInspectResult(hostIps, this.inspectResult).filter(Array.from(this.boundPorts.iterator()).map((port) => port[0]));
|
|
63
63
|
yield (0, wait_for_container_1.waitForContainer)(this.container, this.waitStrategy, this.boundPorts, startTime);
|
|
64
|
+
logger_1.log.info(`Restarted container`, { containerId: this.container.id });
|
|
64
65
|
});
|
|
65
66
|
}
|
|
66
67
|
stopContainer(options = {}) {
|
|
67
68
|
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
-
logger_1.log.info(`Stopping container
|
|
69
|
+
logger_1.log.info(`Stopping container...`, { containerId: this.container.id });
|
|
69
70
|
if (this.containerIsStopping) {
|
|
70
71
|
yield this.containerIsStopping();
|
|
71
72
|
}
|
|
72
73
|
const resolvedOptions = Object.assign({ timeout: 0, removeVolumes: true }, options);
|
|
73
74
|
yield (0, stop_container_1.stopContainer)(this.container, { timeout: resolvedOptions.timeout });
|
|
74
75
|
yield (0, remove_container_1.removeContainer)(this.container, { removeVolumes: resolvedOptions.removeVolumes });
|
|
76
|
+
logger_1.log.info(`Stopped container`, { containerId: this.container.id });
|
|
75
77
|
if (this.containerIsStopped) {
|
|
76
78
|
yield this.containerIsStopped();
|
|
77
79
|
}
|
|
@@ -107,8 +109,11 @@ class StartedGenericContainer {
|
|
|
107
109
|
}
|
|
108
110
|
exec(command) {
|
|
109
111
|
return __awaiter(this, void 0, void 0, function* () {
|
|
110
|
-
const { dockerode,
|
|
111
|
-
|
|
112
|
+
const { dockerode, containerRuntime } = yield (0, docker_client_1.getDockerClient)();
|
|
113
|
+
logger_1.log.debug(`Executing command "${command.join(" ")}"...`, { containerId: this.container.id });
|
|
114
|
+
const output = yield (0, exec_container_1.execContainer)(dockerode, containerRuntime, this.container, command);
|
|
115
|
+
logger_1.log.debug(`Executed command "${command.join(" ")}"...`, { containerId: this.container.id });
|
|
116
|
+
return output;
|
|
112
117
|
});
|
|
113
118
|
}
|
|
114
119
|
logs() {
|
package/dist/src/images.js
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
var _a, _b;
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
4
|
exports.SSHD_IMAGE = exports.REAPER_IMAGE = void 0;
|
|
5
|
-
exports.REAPER_IMAGE = (_a = process.env["RYUK_CONTAINER_IMAGE"]) !== null && _a !== void 0 ? _a : "testcontainers/ryuk:0.
|
|
5
|
+
exports.REAPER_IMAGE = (_a = process.env["RYUK_CONTAINER_IMAGE"]) !== null && _a !== void 0 ? _a : "testcontainers/ryuk:0.4.0";
|
|
6
6
|
exports.SSHD_IMAGE = (_b = process.env["SSHD_CONTAINER_IMAGE"]) !== null && _b !== void 0 ? _b : "testcontainers/sshd:1.1.0";
|
package/dist/src/logger.d.ts
CHANGED
|
@@ -1,36 +1,25 @@
|
|
|
1
1
|
type Message = string;
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
error(message: Message): void;
|
|
9
|
-
}
|
|
10
|
-
declare class DebugLogger implements Logger {
|
|
2
|
+
type Options = {
|
|
3
|
+
containerId?: string;
|
|
4
|
+
imageName?: string;
|
|
5
|
+
};
|
|
6
|
+
export declare class Logger {
|
|
7
|
+
private readonly showLevel;
|
|
11
8
|
private readonly logger;
|
|
12
|
-
constructor(namespace: string);
|
|
13
|
-
enabled(): boolean;
|
|
14
|
-
trace(message: Message): void;
|
|
15
|
-
debug(message: Message): void;
|
|
16
|
-
info(message: Message): void;
|
|
17
|
-
warn(message: Message): void;
|
|
18
|
-
error(message: Message): void;
|
|
19
|
-
}
|
|
20
|
-
export declare class FakeLogger implements Logger {
|
|
21
|
-
readonly traceLogs: Message[];
|
|
22
|
-
readonly debugLogs: Message[];
|
|
23
|
-
readonly infoLogs: Message[];
|
|
24
|
-
readonly warnLogs: Message[];
|
|
25
|
-
readonly errorLogs: Message[];
|
|
9
|
+
constructor(namespace: string, showLevel?: boolean);
|
|
26
10
|
enabled(): boolean;
|
|
27
|
-
trace(message: Message): void;
|
|
28
|
-
debug(message: Message): void;
|
|
29
|
-
info(message: Message): void;
|
|
30
|
-
warn(message: Message): void;
|
|
31
|
-
error(message: Message): void;
|
|
11
|
+
trace(message: Message, options?: Options): void;
|
|
12
|
+
debug(message: Message, options?: Options): void;
|
|
13
|
+
info(message: Message, options?: Options): void;
|
|
14
|
+
warn(message: Message, options?: Options): void;
|
|
15
|
+
error(message: Message, options?: Options): void;
|
|
16
|
+
private formatMessage;
|
|
17
|
+
private renderOptions;
|
|
32
18
|
}
|
|
33
|
-
export declare const log:
|
|
34
|
-
export declare const containerLog:
|
|
35
|
-
export declare const
|
|
19
|
+
export declare const log: Logger;
|
|
20
|
+
export declare const containerLog: Logger;
|
|
21
|
+
export declare const composeLog: Logger;
|
|
22
|
+
export declare const buildLog: Logger;
|
|
23
|
+
export declare const pullLog: Logger;
|
|
24
|
+
export declare const execLog: Logger;
|
|
36
25
|
export {};
|
package/dist/src/logger.js
CHANGED
|
@@ -3,59 +3,49 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.execLog = exports.containerLog = exports.log = exports.
|
|
6
|
+
exports.execLog = exports.pullLog = exports.buildLog = exports.composeLog = exports.containerLog = exports.log = exports.Logger = void 0;
|
|
7
7
|
const debug_1 = __importDefault(require("debug"));
|
|
8
|
-
class
|
|
9
|
-
constructor(namespace) {
|
|
8
|
+
class Logger {
|
|
9
|
+
constructor(namespace, showLevel = true) {
|
|
10
|
+
this.showLevel = showLevel;
|
|
10
11
|
this.logger = (0, debug_1.default)(namespace);
|
|
11
12
|
}
|
|
12
13
|
enabled() {
|
|
13
14
|
return this.logger.enabled;
|
|
14
15
|
}
|
|
15
|
-
trace(message) {
|
|
16
|
-
this.logger(
|
|
16
|
+
trace(message, options) {
|
|
17
|
+
this.logger(this.formatMessage(message, "TRACE", options));
|
|
17
18
|
}
|
|
18
|
-
debug(message) {
|
|
19
|
-
this.logger(
|
|
19
|
+
debug(message, options) {
|
|
20
|
+
this.logger(this.formatMessage(message, "DEBUG", options));
|
|
20
21
|
}
|
|
21
|
-
info(message) {
|
|
22
|
-
this.logger(
|
|
22
|
+
info(message, options) {
|
|
23
|
+
this.logger(this.formatMessage(message, "INFO", options));
|
|
23
24
|
}
|
|
24
|
-
warn(message) {
|
|
25
|
-
this.logger(
|
|
25
|
+
warn(message, options) {
|
|
26
|
+
this.logger(this.formatMessage(message, "WARN", options));
|
|
26
27
|
}
|
|
27
|
-
error(message) {
|
|
28
|
-
this.logger(
|
|
28
|
+
error(message, options) {
|
|
29
|
+
this.logger(this.formatMessage(message, "ERROR", options));
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
constructor() {
|
|
33
|
-
this.traceLogs = [];
|
|
34
|
-
this.debugLogs = [];
|
|
35
|
-
this.infoLogs = [];
|
|
36
|
-
this.warnLogs = [];
|
|
37
|
-
this.errorLogs = [];
|
|
38
|
-
}
|
|
39
|
-
enabled() {
|
|
40
|
-
return true;
|
|
41
|
-
}
|
|
42
|
-
trace(message) {
|
|
43
|
-
this.traceLogs.push(message);
|
|
44
|
-
}
|
|
45
|
-
debug(message) {
|
|
46
|
-
this.debugLogs.push(message);
|
|
47
|
-
}
|
|
48
|
-
info(message) {
|
|
49
|
-
this.infoLogs.push(message);
|
|
50
|
-
}
|
|
51
|
-
warn(message) {
|
|
52
|
-
this.warnLogs.push(message);
|
|
31
|
+
formatMessage(message, level, options) {
|
|
32
|
+
return `${this.showLevel ? `[${level}] ` : ""}${this.renderOptions(options)}${message}`;
|
|
53
33
|
}
|
|
54
|
-
|
|
55
|
-
|
|
34
|
+
renderOptions(options) {
|
|
35
|
+
let str = "";
|
|
36
|
+
if (options === null || options === void 0 ? void 0 : options.containerId) {
|
|
37
|
+
str += `[${options.containerId.substring(0, 12)}] `;
|
|
38
|
+
}
|
|
39
|
+
if (options === null || options === void 0 ? void 0 : options.imageName) {
|
|
40
|
+
str += `[${options.imageName}] `;
|
|
41
|
+
}
|
|
42
|
+
return str;
|
|
56
43
|
}
|
|
57
44
|
}
|
|
58
|
-
exports.
|
|
59
|
-
exports.log = new
|
|
60
|
-
exports.containerLog = new
|
|
61
|
-
exports.
|
|
45
|
+
exports.Logger = Logger;
|
|
46
|
+
exports.log = new Logger("testcontainers");
|
|
47
|
+
exports.containerLog = new Logger("testcontainers:containers", false);
|
|
48
|
+
exports.composeLog = new Logger("testcontainers:compose", false);
|
|
49
|
+
exports.buildLog = new Logger("testcontainers:build", false);
|
|
50
|
+
exports.pullLog = new Logger("testcontainers:pull", false);
|
|
51
|
+
exports.execLog = new Logger("testcontainers:exec", false);
|
|
@@ -19,7 +19,7 @@ const HTTP_MANAGEMENT_PORT = 8222;
|
|
|
19
19
|
const USER_ARGUMENT_KEY = "--user";
|
|
20
20
|
const PASS_ARGUMENT_KEY = "--pass";
|
|
21
21
|
class NatsContainer extends generic_container_1.GenericContainer {
|
|
22
|
-
constructor(image = "nats:2.8-alpine") {
|
|
22
|
+
constructor(image = "nats:2.8.4-alpine") {
|
|
23
23
|
super(image);
|
|
24
24
|
this.args = {};
|
|
25
25
|
this.args[USER_ARGUMENT_KEY] = "test";
|
package/dist/src/network.js
CHANGED
|
@@ -23,10 +23,12 @@ class Network {
|
|
|
23
23
|
}
|
|
24
24
|
start() {
|
|
25
25
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
-
const
|
|
26
|
+
const name = this.uuid.nextUuid();
|
|
27
|
+
const options = Object.assign({ name, driver: "bridge", checkDuplicate: true, internal: false, attachable: false, ingress: false, enableIPv6: false }, this.createNetworkOptions);
|
|
27
28
|
yield reaper_1.ReaperInstance.getInstance();
|
|
29
|
+
logger_1.log.info(`Starting network "${name}"...`);
|
|
28
30
|
const id = yield (0, create_network_1.createNetwork)(options);
|
|
29
|
-
logger_1.log.info(`Started network with ID
|
|
31
|
+
logger_1.log.info(`Started network "${name}" with ID "${id}"`);
|
|
30
32
|
return new StartedNetwork(id, options);
|
|
31
33
|
});
|
|
32
34
|
}
|
|
@@ -45,8 +47,9 @@ class StartedNetwork {
|
|
|
45
47
|
}
|
|
46
48
|
stop() {
|
|
47
49
|
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
-
logger_1.log.info(`Stopping network with ID
|
|
50
|
+
logger_1.log.info(`Stopping network with ID "${this.id}"...`);
|
|
49
51
|
yield (0, remove_network_1.removeNetwork)(this.id);
|
|
52
|
+
logger_1.log.info(`Stopped network with ID "${this.id}"`);
|
|
50
53
|
return new StoppedNetwork();
|
|
51
54
|
});
|
|
52
55
|
}
|
package/dist/src/port-check.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Dockerode from "dockerode";
|
|
2
|
-
import {
|
|
2
|
+
import { ContainerRuntime } from "./docker/types";
|
|
3
3
|
export interface PortCheck {
|
|
4
4
|
isBound(port: number): Promise<boolean>;
|
|
5
5
|
}
|
|
@@ -10,11 +10,11 @@ export declare class HostPortCheck implements PortCheck {
|
|
|
10
10
|
}
|
|
11
11
|
export declare class InternalPortCheck implements PortCheck {
|
|
12
12
|
private readonly dockerode;
|
|
13
|
-
private readonly
|
|
13
|
+
private readonly containerRuntime;
|
|
14
14
|
private readonly container;
|
|
15
15
|
private isDistroless;
|
|
16
16
|
private commandOutputs;
|
|
17
|
-
constructor(dockerode: Dockerode,
|
|
17
|
+
constructor(dockerode: Dockerode, containerRuntime: ContainerRuntime, container: Dockerode.Container);
|
|
18
18
|
isBound(port: number): Promise<boolean>;
|
|
19
19
|
private commandOutputsKey;
|
|
20
20
|
}
|
package/dist/src/port-check.js
CHANGED
|
@@ -39,9 +39,9 @@ class HostPortCheck {
|
|
|
39
39
|
}
|
|
40
40
|
exports.HostPortCheck = HostPortCheck;
|
|
41
41
|
class InternalPortCheck {
|
|
42
|
-
constructor(dockerode,
|
|
42
|
+
constructor(dockerode, containerRuntime, container) {
|
|
43
43
|
this.dockerode = dockerode;
|
|
44
|
-
this.
|
|
44
|
+
this.containerRuntime = containerRuntime;
|
|
45
45
|
this.container = container;
|
|
46
46
|
this.isDistroless = false;
|
|
47
47
|
this.commandOutputs = new Set();
|
|
@@ -54,14 +54,16 @@ class InternalPortCheck {
|
|
|
54
54
|
["/bin/sh", "-c", `nc -vz -w 1 localhost ${port}`],
|
|
55
55
|
["/bin/bash", "-c", `</dev/tcp/localhost/${port}`],
|
|
56
56
|
];
|
|
57
|
-
const commandResults = yield Promise.all(commands.map((command) => (0, exec_container_1.execContainer)(this.dockerode, this.
|
|
57
|
+
const commandResults = yield Promise.all(commands.map((command) => (0, exec_container_1.execContainer)(this.dockerode, this.containerRuntime, this.container, command, false)));
|
|
58
58
|
const isBound = commandResults.some((result) => result.exitCode === 0);
|
|
59
59
|
if (!isBound && logger_1.log.enabled()) {
|
|
60
60
|
const shellExists = commandResults.some((result) => result.exitCode !== 126);
|
|
61
61
|
if (!shellExists) {
|
|
62
62
|
if (!this.isDistroless) {
|
|
63
63
|
this.isDistroless = true;
|
|
64
|
-
logger_1.log.error(`The HostPortWaitStrategy will not work on a distroless image, use an alternate wait strategy
|
|
64
|
+
logger_1.log.error(`The HostPortWaitStrategy will not work on a distroless image, use an alternate wait strategy`, {
|
|
65
|
+
containerId: this.container.id,
|
|
66
|
+
});
|
|
65
67
|
}
|
|
66
68
|
}
|
|
67
69
|
else {
|
|
@@ -70,7 +72,9 @@ class InternalPortCheck {
|
|
|
70
72
|
.filter((result) => result.exitCode !== 126 && result.output.length > 0)
|
|
71
73
|
.forEach((result) => {
|
|
72
74
|
if (!this.commandOutputs.has(this.commandOutputsKey(result.output))) {
|
|
73
|
-
logger_1.log.trace(`Port check result
|
|
75
|
+
logger_1.log.trace(`Port check result exit code ${result.exitCode}: ${result.output}`, {
|
|
76
|
+
containerId: this.container.id,
|
|
77
|
+
});
|
|
74
78
|
this.commandOutputs.add(this.commandOutputsKey(result.output));
|
|
75
79
|
}
|
|
76
80
|
});
|
|
@@ -15,7 +15,7 @@ const logger_1 = require("./logger");
|
|
|
15
15
|
const generic_container_1 = require("./generic-container/generic-container");
|
|
16
16
|
const uuid_1 = require("./uuid");
|
|
17
17
|
const session_id_1 = require("./docker/session-id");
|
|
18
|
-
const docker_client_1 = require("./docker/docker-client");
|
|
18
|
+
const docker_client_1 = require("./docker/client/docker-client");
|
|
19
19
|
const images_1 = require("./images");
|
|
20
20
|
class PortForwarder {
|
|
21
21
|
constructor(sshConnection, container) {
|
|
@@ -24,8 +24,9 @@ class PortForwarder {
|
|
|
24
24
|
}
|
|
25
25
|
exposeHostPort(port) {
|
|
26
26
|
return __awaiter(this, void 0, void 0, function* () {
|
|
27
|
-
logger_1.log.info(`Exposing host port ${port}
|
|
27
|
+
logger_1.log.info(`Exposing host port ${port}...`);
|
|
28
28
|
yield this.sshConnection.remoteForward("localhost", port);
|
|
29
|
+
logger_1.log.info(`Exposed host port ${port}`);
|
|
29
30
|
});
|
|
30
31
|
}
|
|
31
32
|
getNetworkId() {
|
|
@@ -53,7 +54,7 @@ class PortForwarderInstance {
|
|
|
53
54
|
}
|
|
54
55
|
static createInstance() {
|
|
55
56
|
return __awaiter(this, void 0, void 0, function* () {
|
|
56
|
-
logger_1.log.debug(`Creating new Port Forwarder
|
|
57
|
+
logger_1.log.debug(`Creating new Port Forwarder...`);
|
|
57
58
|
const username = "root";
|
|
58
59
|
const password = new uuid_1.RandomUuid().nextUuid();
|
|
59
60
|
const containerPort = process.env["TESTCONTAINERS_SSHD_PORT"]
|
|
@@ -69,10 +70,11 @@ class PortForwarderInstance {
|
|
|
69
70
|
`echo "${username}:$PASSWORD" | chpasswd && /usr/sbin/sshd -D -o PermitRootLogin=yes -o AddressFamily=inet -o GatewayPorts=yes -o AllowAgentForwarding=yes -o AllowTcpForwarding=yes -o KexAlgorithms=+diffie-hellman-group1-sha1 -o HostkeyAlgorithms=+ssh-rsa`,
|
|
70
71
|
])
|
|
71
72
|
.start();
|
|
72
|
-
const host = (yield (0, docker_client_1.
|
|
73
|
+
const host = (yield (0, docker_client_1.getDockerClient)()).host;
|
|
73
74
|
const port = container.getMappedPort(22);
|
|
74
|
-
logger_1.log.debug(`Connecting to Port Forwarder on ${host}:${port}
|
|
75
|
+
logger_1.log.debug(`Connecting to Port Forwarder on "${host}:${port}"...`);
|
|
75
76
|
const connection = yield (0, ssh_remote_port_forward_1.createSshConnection)({ host, port, username, password });
|
|
77
|
+
logger_1.log.debug(`Connected to Port Forwarder on "${host}:${port}"`);
|
|
76
78
|
connection.unref();
|
|
77
79
|
return new PortForwarder(connection, container);
|
|
78
80
|
});
|
package/dist/src/reaper.js
CHANGED
|
@@ -19,8 +19,8 @@ const port_1 = require("./port");
|
|
|
19
19
|
const labels_1 = require("./labels");
|
|
20
20
|
const wait_1 = require("./wait-strategy/wait");
|
|
21
21
|
const retry_strategy_1 = require("./retry-strategy");
|
|
22
|
-
const
|
|
23
|
-
const docker_client_1 = require("./docker/docker-client");
|
|
22
|
+
const remote_docker_unix_socket_path_1 = require("./docker/remote-docker-unix-socket-path");
|
|
23
|
+
const docker_client_1 = require("./docker/client/docker-client");
|
|
24
24
|
class RealReaper {
|
|
25
25
|
constructor(container, socket) {
|
|
26
26
|
this.container = container;
|
|
@@ -77,7 +77,7 @@ class ReaperInstance {
|
|
|
77
77
|
return process.env.TESTCONTAINERS_RYUK_PRIVILEGED === "true";
|
|
78
78
|
}
|
|
79
79
|
static createDisabledInstance() {
|
|
80
|
-
logger_1.log.debug(`Not creating new Reaper for session
|
|
80
|
+
logger_1.log.debug(`Not creating new Reaper for session "${session_id_1.sessionId}"`);
|
|
81
81
|
return Promise.resolve(new DisabledReaper());
|
|
82
82
|
}
|
|
83
83
|
static createRealInstance() {
|
|
@@ -85,13 +85,15 @@ class ReaperInstance {
|
|
|
85
85
|
const containerPort = process.env["TESTCONTAINERS_RYUK_PORT"]
|
|
86
86
|
? { container: 8080, host: Number(process.env["TESTCONTAINERS_RYUK_PORT"]) }
|
|
87
87
|
: 8080;
|
|
88
|
-
|
|
88
|
+
const dockerClient = yield (0, docker_client_1.getDockerClient)();
|
|
89
|
+
const remoteDockerUnixSocketPath = (0, remote_docker_unix_socket_path_1.getRemoteDockerUnixSocketPath)(dockerClient);
|
|
90
|
+
logger_1.log.debug(`Creating new Reaper for session "${session_id_1.sessionId}" with socket path "${remoteDockerUnixSocketPath}"...`);
|
|
89
91
|
const container = new generic_container_1.GenericContainer(images_1.REAPER_IMAGE)
|
|
90
92
|
.withName(`testcontainers-ryuk-${session_id_1.sessionId}`)
|
|
91
93
|
.withExposedPorts(containerPort)
|
|
92
94
|
.withBindMounts([
|
|
93
95
|
{
|
|
94
|
-
source:
|
|
96
|
+
source: remoteDockerUnixSocketPath,
|
|
95
97
|
target: "/var/run/docker.sock",
|
|
96
98
|
},
|
|
97
99
|
])
|
|
@@ -106,7 +108,7 @@ class ReaperInstance {
|
|
|
106
108
|
const retryStrategy = new retry_strategy_1.IntervalRetryStrategy(1000);
|
|
107
109
|
const retryResult = yield retryStrategy.retryUntil((attempt) => {
|
|
108
110
|
return new Promise((resolve) => {
|
|
109
|
-
logger_1.log.debug(`Connecting to Reaper (attempt ${attempt + 1})
|
|
111
|
+
logger_1.log.debug(`Connecting to Reaper (attempt ${attempt + 1}) on "${host}:${port}"...`, { containerId });
|
|
110
112
|
const socket = new net_1.Socket();
|
|
111
113
|
socket
|
|
112
114
|
.unref()
|
|
@@ -114,21 +116,25 @@ class ReaperInstance {
|
|
|
114
116
|
.on("error", (err) => logger_1.log.error(`Reaper ${containerId} socket error: ${err}`))
|
|
115
117
|
.on("close", (hadError) => {
|
|
116
118
|
if (hadError) {
|
|
117
|
-
logger_1.log.error(`Connection to Reaper
|
|
119
|
+
logger_1.log.error(`Connection to Reaper closed with error`, { containerId });
|
|
118
120
|
}
|
|
119
121
|
else {
|
|
120
|
-
logger_1.log.warn(`Connection to Reaper
|
|
122
|
+
logger_1.log.warn(`Connection to Reaper closed`, { containerId });
|
|
121
123
|
}
|
|
122
124
|
resolve(undefined);
|
|
123
125
|
})
|
|
124
126
|
.connect((0, port_1.getContainerPort)(port), host, () => {
|
|
125
|
-
logger_1.log.debug(`Connected to Reaper
|
|
127
|
+
logger_1.log.debug(`Connected to Reaper`, { containerId });
|
|
126
128
|
socket.write(`label=${labels_1.LABEL_TESTCONTAINERS_SESSION_ID}=${session_id_1.sessionId}\r\n`);
|
|
127
129
|
const reaper = new RealReaper(startedContainer, socket);
|
|
128
130
|
resolve(reaper);
|
|
129
131
|
});
|
|
130
132
|
});
|
|
131
|
-
}, (result) => result !== undefined, () =>
|
|
133
|
+
}, (result) => result !== undefined, () => {
|
|
134
|
+
const message = `Failed to connect to Reaper`;
|
|
135
|
+
logger_1.log.error(message, { containerId });
|
|
136
|
+
return new Error(message);
|
|
137
|
+
}, 4000);
|
|
132
138
|
if (retryResult instanceof RealReaper) {
|
|
133
139
|
return retryResult;
|
|
134
140
|
}
|
|
@@ -21,20 +21,18 @@ class CredentialProvider {
|
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
23
|
const programName = `docker-credential-${credentialProviderName}`;
|
|
24
|
-
logger_1.log.debug(`Executing Docker credential provider
|
|
24
|
+
logger_1.log.debug(`Executing Docker credential provider "${programName}"`);
|
|
25
25
|
const credentials = yield this.listCredentials(programName);
|
|
26
26
|
if (!Object.keys(credentials).some((aRegistry) => (0, registry_matches_1.registryMatches)(aRegistry, registry))) {
|
|
27
|
-
logger_1.log.debug(`No credential found for registry
|
|
27
|
+
logger_1.log.debug(`No credential found for registry "${registry}"`);
|
|
28
28
|
return undefined;
|
|
29
29
|
}
|
|
30
30
|
const response = yield this.runCredentialProvider(registry, programName);
|
|
31
|
-
|
|
31
|
+
return {
|
|
32
32
|
username: response.Username,
|
|
33
33
|
password: response.Secret,
|
|
34
34
|
registryAddress: response.ServerURL,
|
|
35
35
|
};
|
|
36
|
-
logger_1.log.debug(`Docker credential provider found auth config for ${registry}`);
|
|
37
|
-
return authConfig;
|
|
38
36
|
});
|
|
39
37
|
}
|
|
40
38
|
listCredentials(providerName) {
|
|
@@ -47,18 +47,18 @@ const registryAuthLocators = [new cred_helpers_1.CredHelpers(), new creds_store_
|
|
|
47
47
|
const authsCache = new Map();
|
|
48
48
|
const getAuthConfig = (registry) => __awaiter(void 0, void 0, void 0, function* () {
|
|
49
49
|
if (authsCache.has(registry)) {
|
|
50
|
-
logger_1.log.debug(`
|
|
50
|
+
logger_1.log.debug(`Auth config cache hit for registry "${registry}"`);
|
|
51
51
|
return authsCache.get(registry);
|
|
52
52
|
}
|
|
53
53
|
for (const registryAuthLocator of registryAuthLocators) {
|
|
54
54
|
const authConfig = yield registryAuthLocator.getAuthConfig(registry, yield dockerConfig);
|
|
55
55
|
if (authConfig) {
|
|
56
|
-
logger_1.log.debug(`
|
|
56
|
+
logger_1.log.debug(`Auth config found for registry "${registry}": ${registryAuthLocator.getName()}`);
|
|
57
57
|
authsCache.set(registry, authConfig);
|
|
58
58
|
return authConfig;
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
-
logger_1.log.debug(`No registry auth locator found for registry
|
|
61
|
+
logger_1.log.debug(`No registry auth locator found for registry "${registry}"`);
|
|
62
62
|
authsCache.set(registry, undefined);
|
|
63
63
|
return undefined;
|
|
64
64
|
});
|
package/dist/src/system-info.js
CHANGED
|
@@ -19,15 +19,12 @@ const getSystemInfo = (dockerode) => __awaiter(void 0, void 0, void 0, function*
|
|
|
19
19
|
if (systemInfo !== undefined) {
|
|
20
20
|
return systemInfo;
|
|
21
21
|
}
|
|
22
|
-
logger_1.log.debug("Fetching system info");
|
|
22
|
+
logger_1.log.debug("Fetching system info...");
|
|
23
23
|
const nodeInfo = getNodeInfo();
|
|
24
24
|
const dockerInfo = yield (0, get_info_1.getDockerInfo)(dockerode);
|
|
25
25
|
const dockerComposeInfo = yield getDockerComposeInfo();
|
|
26
26
|
systemInfo = { nodeInfo, dockerInfo, dockerComposeInfo };
|
|
27
|
-
logger_1.log.debug(`
|
|
28
|
-
System: Node version: ${nodeInfo.version}, Platform: ${nodeInfo.platform}, Arch: ${nodeInfo.architecture}
|
|
29
|
-
Container runtime: OS: ${dockerInfo.operatingSystem}, Version: ${dockerInfo.serverVersion}, Arch: ${dockerInfo.architecture}, CPUs: ${dockerInfo.cpus}, Memory: ${dockerInfo.memory}
|
|
30
|
-
Compose: Installed: ${dockerComposeInfo !== undefined}, Version: ${(_a = dockerComposeInfo === null || dockerComposeInfo === void 0 ? void 0 : dockerComposeInfo.version) !== null && _a !== void 0 ? _a : "N/A"}`);
|
|
27
|
+
logger_1.log.debug(`Node version: ${nodeInfo.version}, Platform: ${nodeInfo.platform}, Arch: ${nodeInfo.architecture}, OS: ${dockerInfo.operatingSystem}, Version: ${dockerInfo.serverVersion}, Arch: ${dockerInfo.architecture}, CPUs: ${dockerInfo.cpus}, Memory: ${dockerInfo.memory}, Compose installed: ${dockerComposeInfo !== undefined}, Compose version: ${(_a = dockerComposeInfo === null || dockerComposeInfo === void 0 ? void 0 : dockerComposeInfo.version) !== null && _a !== void 0 ? _a : "N/A"}`);
|
|
31
28
|
return systemInfo;
|
|
32
29
|
});
|
|
33
30
|
exports.getSystemInfo = getSystemInfo;
|
|
@@ -30,6 +30,7 @@ export interface TestContainer {
|
|
|
30
30
|
withCopyContentToContainer(contentsToCopy: ContentToCopy[]): this;
|
|
31
31
|
withWorkingDir(workingDir: string): this;
|
|
32
32
|
withResourcesQuota(resourcesQuota: ResourcesQuota): this;
|
|
33
|
+
withLogConsumer(logConsumer: (stream: Readable) => unknown): this;
|
|
33
34
|
}
|
|
34
35
|
export interface RestartOptions {
|
|
35
36
|
timeout: number;
|