testcontainers 9.5.0 → 9.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.json +14 -14
- package/dist/src/docker/docker-client-config.js +42 -36
- package/dist/src/docker/docker-client.d.ts +2 -0
- package/dist/src/docker/docker-client.js +6 -5
- package/dist/src/docker/functions/container/attach-container.js +1 -1
- package/dist/src/docker/functions/container/create-container.js +6 -4
- package/dist/src/docker/functions/container/exec-container.d.ts +2 -1
- package/dist/src/docker/functions/container/exec-container.js +15 -8
- package/dist/src/docker/functions/container/get-container.js +1 -1
- package/dist/src/docker/functions/container/inspect-container.js +1 -1
- package/dist/src/docker/functions/container/put-container-archive.js +5 -2
- 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 +8 -3
- package/dist/src/docker/functions/image/image-exists.js +11 -8
- package/dist/src/docker/functions/image/pull-image.js +3 -3
- package/dist/src/docker/functions/network/connect-network.js +3 -2
- package/dist/src/docker/functions/network/create-network.js +2 -1
- package/dist/src/docker/functions/network/remove-network.js +3 -2
- package/dist/src/docker/functions/run-in-container.js +6 -6
- package/dist/src/docker/pull-stream-parser.d.ts +0 -1
- package/dist/src/docker/pull-stream-parser.js +2 -41
- package/dist/src/docker/resolve-host.d.ts +2 -1
- package/dist/src/docker/resolve-host.js +7 -6
- package/dist/src/docker-compose/default-docker-compose-options.js +4 -2
- 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.d.ts +1 -1
- package/dist/src/docker-compose-environment/docker-compose-environment.js +11 -10
- package/dist/src/generic-container/generic-container-builder.js +1 -1
- package/dist/src/generic-container/generic-container.d.ts +6 -2
- package/dist/src/generic-container/generic-container.js +30 -17
- package/dist/src/generic-container/started-generic-container.d.ts +2 -0
- package/dist/src/generic-container/started-generic-container.js +26 -7
- 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/elasticsearch/elasticsearch-container.js +1 -1
- package/dist/src/modules/nats/nats-container.js +1 -1
- package/dist/src/network.d.ts +1 -0
- package/dist/src/network.js +11 -5
- package/dist/src/port-check.d.ts +4 -1
- package/dist/src/port-check.js +10 -4
- package/dist/src/port-forwarder.js +5 -3
- package/dist/src/reaper.js +11 -7
- 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 +2 -6
- package/dist/src/uuid.js +1 -1
- package/dist/src/wait-for-container.d.ts +1 -1
- package/dist/src/wait-for-container.js +6 -6
- package/dist/src/wait-strategy/composite-wait-strategy.d.ts +11 -0
- package/dist/src/wait-strategy/composite-wait-strategy.js +54 -0
- package/dist/src/wait-strategy/health-check-wait-strategy.js +7 -3
- package/dist/src/wait-strategy/host-port-wait-strategy.d.ts +1 -5
- package/dist/src/wait-strategy/host-port-wait-strategy.js +21 -17
- package/dist/src/wait-strategy/http-wait-strategy.d.ts +1 -1
- package/dist/src/wait-strategy/http-wait-strategy.js +8 -2
- package/dist/src/wait-strategy/log-wait-strategy.d.ts +1 -1
- package/dist/src/wait-strategy/log-wait-strategy.js +8 -7
- package/dist/src/wait-strategy/shell-wait-strategy.js +7 -4
- package/dist/src/wait-strategy/startup-check-strategy.js +6 -1
- package/dist/src/wait-strategy/wait-strategy.d.ts +8 -3
- package/dist/src/wait-strategy/wait-strategy.js +8 -0
- package/dist/src/wait-strategy/wait.d.ts +3 -0
- package/dist/src/wait-strategy/wait.js +8 -0
- package/package.json +14 -14
- package/dist/src/docker/functions/image/list-images.d.ts +0 -3
- package/dist/src/docker/functions/image/list-images.js +0 -34
- package/dist/src/wait-strategy/default-wait-strategy.d.ts +0 -3
- package/dist/src/wait-strategy/default-wait-strategy.js +0 -7
package/dist/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "testcontainers",
|
|
3
3
|
"author": "Cristian Greco",
|
|
4
|
-
"version": "9.
|
|
4
|
+
"version": "9.7.0",
|
|
5
5
|
"main": "dist/src/index",
|
|
6
6
|
"types": "dist/src/index",
|
|
7
7
|
"keywords": [
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"build": "npm run clean && tsc -p tsconfig.prod.json",
|
|
28
28
|
"docs:serve": "docker-compose up",
|
|
29
29
|
"clean": "rimraf dist",
|
|
30
|
-
"test": "cross-env DEBUG=testcontainers
|
|
31
|
-
"test:ci": "
|
|
30
|
+
"test": "cross-env DEBUG=testcontainers* jest",
|
|
31
|
+
"test:ci": "npm run test -- --runInBand --coverage",
|
|
32
32
|
"format": "prettier --write package.json \"src/**/*.ts\"",
|
|
33
33
|
"lint": "eslint --fix package.json \"src/**/*.ts\"",
|
|
34
34
|
"lint:ci": "eslint package.json \"src/**/*.ts\" --max-warnings=0",
|
|
@@ -56,31 +56,31 @@
|
|
|
56
56
|
"@types/async-lock": "^1.4.0",
|
|
57
57
|
"@types/byline": "^4.2.33",
|
|
58
58
|
"@types/debug": "4.1.7",
|
|
59
|
-
"@types/jest": "^29.5.
|
|
60
|
-
"@types/node": "^18.
|
|
59
|
+
"@types/jest": "^29.5.1",
|
|
60
|
+
"@types/node": "^18.16.2",
|
|
61
61
|
"@types/node-fetch": "^2.6.3",
|
|
62
62
|
"@types/pg": "^8.6.6",
|
|
63
63
|
"@types/properties-reader": "^2.1.1",
|
|
64
64
|
"@types/tar-fs": "^2.0.1",
|
|
65
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
66
|
-
"@typescript-eslint/parser": "^5.
|
|
67
|
-
"arangojs": "^8.2.
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^5.59.1",
|
|
66
|
+
"@typescript-eslint/parser": "^5.59.1",
|
|
67
|
+
"arangojs": "^8.2.1",
|
|
68
68
|
"cross-env": "^7.0.3",
|
|
69
|
-
"eslint": "^8.
|
|
69
|
+
"eslint": "^8.39.0",
|
|
70
70
|
"eslint-config-prettier": "^8.8.0",
|
|
71
71
|
"eslint-plugin-prettier": "^4.2.1",
|
|
72
72
|
"husky": "^8.0.3",
|
|
73
73
|
"jest": "^29.5.0",
|
|
74
74
|
"kafkajs": "^2.2.4",
|
|
75
|
-
"lint-staged": "^13.2.
|
|
76
|
-
"mongoose": "^6.10.
|
|
75
|
+
"lint-staged": "^13.2.2",
|
|
76
|
+
"mongoose": "^6.10.5",
|
|
77
77
|
"mysql2": "^2.3.3",
|
|
78
78
|
"nats": "^2.13.1",
|
|
79
|
-
"neo4j-driver": "^5.
|
|
79
|
+
"neo4j-driver": "^5.7.0",
|
|
80
80
|
"pg": "^8.10.0",
|
|
81
|
-
"prettier": "^2.8.
|
|
81
|
+
"prettier": "^2.8.8",
|
|
82
82
|
"rimraf": "^3.0.2",
|
|
83
|
-
"ts-jest": "^29.0
|
|
83
|
+
"ts-jest": "^29.1.0",
|
|
84
84
|
"ts-node": "^10.9.1",
|
|
85
85
|
"typescript": "^4.9.5",
|
|
86
86
|
"wait-for-expect": "^3.0.2"
|
|
@@ -20,47 +20,53 @@ const fs_1 = require("fs");
|
|
|
20
20
|
const promises_1 = require("fs/promises");
|
|
21
21
|
const properties_reader_1 = __importDefault(require("properties-reader"));
|
|
22
22
|
const getDockerClientConfig = (env = process.env) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
23
|
+
const dockerClientConfig = Object.assign(Object.assign({}, (yield loadFromFile())), loadFromEnv(env));
|
|
24
|
+
logDockerClientConfig(dockerClientConfig);
|
|
25
|
+
return dockerClientConfig;
|
|
26
|
+
});
|
|
27
|
+
exports.getDockerClientConfig = getDockerClientConfig;
|
|
28
|
+
function loadFromFile() {
|
|
29
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
30
|
+
const file = path_1.default.resolve((0, os_1.homedir)(), ".testcontainers.properties");
|
|
31
|
+
const dockerClientConfig = {};
|
|
32
|
+
if ((0, fs_1.existsSync)(file)) {
|
|
33
|
+
logger_1.log.debug(`Found ".testcontainers.properties" file`);
|
|
34
|
+
const string = yield (0, promises_1.readFile)(file, { encoding: "utf-8" });
|
|
35
|
+
const properties = (0, properties_reader_1.default)("").read(string);
|
|
36
|
+
const host = properties.get("docker.host");
|
|
37
|
+
if (host !== null) {
|
|
38
|
+
dockerClientConfig.dockerHost = host;
|
|
39
|
+
}
|
|
40
|
+
const tlsVerify = properties.get("docker.tls.verify");
|
|
41
|
+
if (tlsVerify !== null) {
|
|
42
|
+
dockerClientConfig.dockerTlsVerify = `${tlsVerify}`;
|
|
43
|
+
}
|
|
44
|
+
const certPath = properties.get("docker.cert.path");
|
|
45
|
+
if (certPath !== null) {
|
|
46
|
+
dockerClientConfig.dockerCertPath = certPath;
|
|
47
|
+
}
|
|
42
48
|
}
|
|
43
|
-
|
|
49
|
+
return dockerClientConfig;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function loadFromEnv(env) {
|
|
53
|
+
const dockerClientConfig = {};
|
|
44
54
|
if (env["DOCKER_HOST"] !== undefined) {
|
|
45
|
-
dockerHost = env["DOCKER_HOST"];
|
|
55
|
+
dockerClientConfig.dockerHost = env["DOCKER_HOST"];
|
|
46
56
|
}
|
|
47
57
|
if (env["DOCKER_TLS_VERIFY"] !== undefined) {
|
|
48
|
-
dockerTlsVerify = env["DOCKER_TLS_VERIFY"];
|
|
58
|
+
dockerClientConfig.dockerTlsVerify = env["DOCKER_TLS_VERIFY"];
|
|
49
59
|
}
|
|
50
60
|
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}, `;
|
|
61
|
+
dockerClientConfig.dockerCertPath = env["DOCKER_CERT_PATH"];
|
|
59
62
|
}
|
|
60
|
-
|
|
61
|
-
|
|
63
|
+
return dockerClientConfig;
|
|
64
|
+
}
|
|
65
|
+
function logDockerClientConfig(config) {
|
|
66
|
+
const configurations = Object.entries(config)
|
|
67
|
+
.filter(([, value]) => value !== undefined)
|
|
68
|
+
.map(([key, value]) => `${key}: "${value}"`);
|
|
69
|
+
if (configurations.length > 0) {
|
|
70
|
+
logger_1.log.debug(`Loaded Docker client configuration, ${configurations.join(", ")}`);
|
|
62
71
|
}
|
|
63
|
-
|
|
64
|
-
return { dockerHost, dockerTlsVerify, dockerCertPath };
|
|
65
|
-
});
|
|
66
|
-
exports.getDockerClientConfig = getDockerClientConfig;
|
|
72
|
+
}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import Dockerode from "dockerode";
|
|
3
3
|
import { HostIps } from "./lookup-host-ips";
|
|
4
|
+
export type Provider = "docker" | "podman";
|
|
4
5
|
type DockerClient = {
|
|
5
6
|
uri: string;
|
|
7
|
+
provider: Provider;
|
|
6
8
|
host: string;
|
|
7
9
|
hostIps: HostIps;
|
|
8
10
|
dockerode: Dockerode;
|
|
@@ -38,17 +38,18 @@ const getDockerClient = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
38
38
|
yield strategy.init();
|
|
39
39
|
}
|
|
40
40
|
if (strategy.isApplicable()) {
|
|
41
|
-
logger_1.log.debug(`Found
|
|
41
|
+
logger_1.log.debug(`Found Docker client strategy "${strategy.getName()}"`);
|
|
42
42
|
const { uri, dockerode, composeEnvironment } = yield strategy.getDockerClient();
|
|
43
|
-
logger_1.log.debug(`Testing Docker client strategy
|
|
43
|
+
logger_1.log.debug(`Testing Docker client strategy "${uri}"...`);
|
|
44
44
|
if (yield isDockerDaemonReachable(dockerode)) {
|
|
45
45
|
const indexServerAddress = (yield (0, system_info_1.getSystemInfo)(dockerode)).dockerInfo.indexServerAddress;
|
|
46
|
-
const
|
|
46
|
+
const provider = uri.includes("podman.sock") ? "podman" : "docker";
|
|
47
|
+
const host = yield (0, resolve_host_1.resolveHost)(dockerode, provider, indexServerAddress, uri);
|
|
47
48
|
const hostIps = yield (0, lookup_host_ips_1.lookupHostIps)(host);
|
|
48
|
-
logger_1.log.info(`Using Docker client strategy
|
|
49
|
+
logger_1.log.info(`Using Docker client strategy "${strategy.getName()}", Docker host "${host}" (${hostIps
|
|
49
50
|
.map((hostIp) => hostIp.address)
|
|
50
51
|
.join(", ")})`);
|
|
51
|
-
return { uri, host, hostIps, dockerode, indexServerAddress, composeEnvironment };
|
|
52
|
+
return { uri, provider, host, hostIps, dockerode, indexServerAddress, composeEnvironment };
|
|
52
53
|
}
|
|
53
54
|
else {
|
|
54
55
|
logger_1.log.warn(`Docker client strategy ${strategy.getName()} is not reachable`);
|
|
@@ -18,7 +18,7 @@ const attachContainer = (dockerode, container) => __awaiter(void 0, void 0, void
|
|
|
18
18
|
return (0, demux_stream_1.demuxStream)(dockerode, stream);
|
|
19
19
|
}
|
|
20
20
|
catch (err) {
|
|
21
|
-
logger_1.log.error(`Failed to attach to container ${container.id
|
|
21
|
+
logger_1.log.error(`Failed to attach to container: ${err}`, { containerId: container.id });
|
|
22
22
|
throw err;
|
|
23
23
|
}
|
|
24
24
|
});
|
|
@@ -17,9 +17,9 @@ const create_labels_1 = require("../create-labels");
|
|
|
17
17
|
const createContainer = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
18
18
|
var _a, _b;
|
|
19
19
|
try {
|
|
20
|
-
logger_1.log.info(`Creating container for image
|
|
20
|
+
logger_1.log.info(`Creating container for image "${options.imageName}"...`);
|
|
21
21
|
const { dockerode } = yield (0, docker_client_1.dockerClient)();
|
|
22
|
-
|
|
22
|
+
const container = yield dockerode.createContainer({
|
|
23
23
|
name: options.name,
|
|
24
24
|
User: options.user,
|
|
25
25
|
Image: options.imageName.toString(),
|
|
@@ -47,9 +47,11 @@ const createContainer = (options) => __awaiter(void 0, void 0, void 0, function*
|
|
|
47
47
|
NanoCpus: (_b = options.resourcesQuota) === null || _b === void 0 ? void 0 : _b.cpu,
|
|
48
48
|
},
|
|
49
49
|
});
|
|
50
|
+
logger_1.log.info(`Created container for image "${options.imageName}"`, { containerId: container.id });
|
|
51
|
+
return container;
|
|
50
52
|
}
|
|
51
53
|
catch (err) {
|
|
52
|
-
logger_1.log.error(`Failed to create container for image ${options.imageName}: ${err}`);
|
|
54
|
+
logger_1.log.error(`Failed to create container for image "${options.imageName}": ${err}`);
|
|
53
55
|
throw err;
|
|
54
56
|
}
|
|
55
57
|
});
|
|
@@ -72,7 +74,7 @@ const getPortBindings = (exposedPorts) => {
|
|
|
72
74
|
dockerodePortBindings[exposedPort.container] = [{ HostPort: exposedPort.host.toString() }];
|
|
73
75
|
}
|
|
74
76
|
else {
|
|
75
|
-
dockerodePortBindings[exposedPort] = [{ HostPort: "
|
|
77
|
+
dockerodePortBindings[exposedPort] = [{ HostPort: "" }];
|
|
76
78
|
}
|
|
77
79
|
}
|
|
78
80
|
return dockerodePortBindings;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { ExecResult } from "../../types";
|
|
2
2
|
import Dockerode from "dockerode";
|
|
3
|
-
|
|
3
|
+
import { Provider } from "../../docker-client";
|
|
4
|
+
export declare const execContainer: (dockerode: Dockerode, provider: Provider, container: Dockerode.Container, command: string[], shouldLog?: boolean) => Promise<ExecResult>;
|
|
@@ -15,7 +15,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.execContainer = void 0;
|
|
16
16
|
const logger_1 = require("../../../logger");
|
|
17
17
|
const byline_1 = __importDefault(require("byline"));
|
|
18
|
-
const
|
|
18
|
+
const demux_stream_1 = require("../demux-stream");
|
|
19
|
+
const execContainer = (dockerode, provider, container, command, shouldLog = true) => __awaiter(void 0, void 0, void 0, function* () {
|
|
19
20
|
const chunks = [];
|
|
20
21
|
try {
|
|
21
22
|
const exec = yield container.exec({
|
|
@@ -23,29 +24,35 @@ const execContainer = (container, command, shouldLog = true) => __awaiter(void 0
|
|
|
23
24
|
AttachStdout: true,
|
|
24
25
|
AttachStderr: true,
|
|
25
26
|
});
|
|
26
|
-
const stream = yield startExec(exec);
|
|
27
|
+
const stream = yield startExec(dockerode, provider, exec, container);
|
|
27
28
|
stream.on("data", (chunk) => chunks.push(chunk));
|
|
28
29
|
if (shouldLog && logger_1.execLog.enabled()) {
|
|
29
|
-
(0, byline_1.default)(stream).on("data", (line) => logger_1.execLog.trace(
|
|
30
|
+
(0, byline_1.default)(stream).on("data", (line) => logger_1.execLog.trace(line, { containerId: container.id }));
|
|
30
31
|
}
|
|
31
32
|
const exitCode = yield waitForExec(exec, stream);
|
|
32
33
|
stream.destroy();
|
|
33
34
|
return { output: chunks.join(""), exitCode };
|
|
34
35
|
}
|
|
35
36
|
catch (err) {
|
|
36
|
-
logger_1.log.error(`Failed to exec container
|
|
37
|
+
logger_1.log.error(`Failed to exec container with command "${command.join(" ")}": ${err}: ${chunks.join("")}`, {
|
|
38
|
+
containerId: container.id,
|
|
39
|
+
});
|
|
37
40
|
throw err;
|
|
38
41
|
}
|
|
39
42
|
});
|
|
40
43
|
exports.execContainer = execContainer;
|
|
41
|
-
const startExec = (exec) => __awaiter(void 0, void 0, void 0, function* () {
|
|
44
|
+
const startExec = (dockerode, provider, exec, container) => __awaiter(void 0, void 0, void 0, function* () {
|
|
42
45
|
try {
|
|
43
46
|
const stream = yield exec.start({ stdin: true, Detach: false, Tty: true });
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
if (provider === "podman") {
|
|
48
|
+
return (0, demux_stream_1.demuxStream)(dockerode, stream);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
return stream;
|
|
52
|
+
}
|
|
46
53
|
}
|
|
47
54
|
catch (err) {
|
|
48
|
-
logger_1.log.error(`Failed to start exec: ${err}
|
|
55
|
+
logger_1.log.error(`Failed to start exec: ${err}`, { containerId: container.id });
|
|
49
56
|
throw err;
|
|
50
57
|
}
|
|
51
58
|
});
|
|
@@ -42,7 +42,7 @@ const getContainerByHash = (hash) => __awaiter(void 0, void 0, void 0, function*
|
|
|
42
42
|
}
|
|
43
43
|
}
|
|
44
44
|
catch (err) {
|
|
45
|
-
logger_1.log.error(`Failed to get container by hash
|
|
45
|
+
logger_1.log.error(`Failed to get container by hash "${hash}": ${err}`);
|
|
46
46
|
throw err;
|
|
47
47
|
}
|
|
48
48
|
});
|
|
@@ -31,7 +31,7 @@ const inspectContainer = (container) => __awaiter(void 0, void 0, void 0, functi
|
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
catch (err) {
|
|
34
|
-
logger_1.log.error(`Failed to inspect container ${container.id
|
|
34
|
+
logger_1.log.error(`Failed to inspect container: ${err}`, { containerId: container.id });
|
|
35
35
|
throw err;
|
|
36
36
|
}
|
|
37
37
|
});
|
|
@@ -10,13 +10,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
12
|
exports.putContainerArchive = void 0;
|
|
13
|
+
const stream_1 = require("stream");
|
|
13
14
|
const logger_1 = require("../../../logger");
|
|
15
|
+
const stream_utils_1 = require("../../../stream-utils");
|
|
14
16
|
const putContainerArchive = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
15
17
|
try {
|
|
16
|
-
yield options.container.putArchive(options.stream, { path: options.containerPath });
|
|
18
|
+
const stream = yield options.container.putArchive(options.stream, { path: options.containerPath });
|
|
19
|
+
yield (0, stream_utils_1.streamToString)(stream_1.Readable.from(stream));
|
|
17
20
|
}
|
|
18
21
|
catch (err) {
|
|
19
|
-
logger_1.log.error(`Failed to put archive to container ${options.container.id
|
|
22
|
+
logger_1.log.error(`Failed to put archive to container: ${err}`, { containerId: options.container.id });
|
|
20
23
|
throw err;
|
|
21
24
|
}
|
|
22
25
|
});
|
|
@@ -16,7 +16,7 @@ const removeContainer = (container, options) => __awaiter(void 0, void 0, void 0
|
|
|
16
16
|
yield container.remove({ v: options.removeVolumes });
|
|
17
17
|
}
|
|
18
18
|
catch (err) {
|
|
19
|
-
logger_1.log.error(`Failed to remove container ${container.id
|
|
19
|
+
logger_1.log.error(`Failed to remove container: ${err}`, { containerId: container.id });
|
|
20
20
|
throw err;
|
|
21
21
|
}
|
|
22
22
|
});
|
|
@@ -16,7 +16,7 @@ const restartContainer = (container, options) => __awaiter(void 0, void 0, void
|
|
|
16
16
|
yield container.restart({ t: options.timeout / 1000 });
|
|
17
17
|
}
|
|
18
18
|
catch (err) {
|
|
19
|
-
logger_1.log.error(`Failed to restart container ${container.id
|
|
19
|
+
logger_1.log.error(`Failed to restart container: ${err}`, { containerId: container.id });
|
|
20
20
|
throw err;
|
|
21
21
|
}
|
|
22
22
|
});
|
|
@@ -16,7 +16,7 @@ const startContainer = (container) => __awaiter(void 0, void 0, void 0, function
|
|
|
16
16
|
yield container.start();
|
|
17
17
|
}
|
|
18
18
|
catch (err) {
|
|
19
|
-
logger_1.log.error(`Failed to start container ${container.id
|
|
19
|
+
logger_1.log.error(`Failed to start container: ${err}`, { containerId: container.id });
|
|
20
20
|
throw err;
|
|
21
21
|
}
|
|
22
22
|
});
|
|
@@ -18,10 +18,10 @@ const stopContainer = (container, options) => __awaiter(void 0, void 0, void 0,
|
|
|
18
18
|
}
|
|
19
19
|
catch (err) {
|
|
20
20
|
if (err.statusCode === 304) {
|
|
21
|
-
logger_1.log.info(`Container has already been stopped:
|
|
21
|
+
logger_1.log.info(`Container has already been stopped`, { containerId: container.id });
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
24
|
-
logger_1.log.error(`Failed to stop container ${container.id
|
|
24
|
+
logger_1.log.error(`Failed to stop container: ${err}`, { containerId: container.id });
|
|
25
25
|
throw err;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -6,9 +6,6 @@ const labels_1 = require("../../labels");
|
|
|
6
6
|
const package_json_1 = require("../../../package.json");
|
|
7
7
|
const createLabels = (reusable, dockerImageName, extraLabels = {}) => {
|
|
8
8
|
const labels = Object.assign(Object.assign({}, extraLabels), { [labels_1.LABEL_TESTCONTAINERS]: "true", [labels_1.LABEL_TESTCONTAINERS_LANG]: "node", [labels_1.LABEL_TESTCONTAINERS_VERSION]: package_json_1.version });
|
|
9
|
-
if (dockerImageName && dockerImageName.isReaper()) {
|
|
10
|
-
return labels;
|
|
11
|
-
}
|
|
12
9
|
if (!reusable) {
|
|
13
10
|
labels[labels_1.LABEL_TESTCONTAINERS_SESSION_ID] = session_id_1.sessionId;
|
|
14
11
|
}
|
|
@@ -23,7 +23,7 @@ const fs_1 = require("fs");
|
|
|
23
23
|
const dockerignore_1 = __importDefault(require("@balena/dockerignore"));
|
|
24
24
|
const buildImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
25
|
try {
|
|
26
|
-
logger_1.log.info(`Building image
|
|
26
|
+
logger_1.log.info(`Building image "${options.imageName.toString()}" with context "${options.context}"...`);
|
|
27
27
|
const isDockerIgnored = yield createIsDockerIgnoredFunction(options.context);
|
|
28
28
|
const tarStream = tar_fs_1.default.pack(options.context, {
|
|
29
29
|
ignore: (aPath) => {
|
|
@@ -46,16 +46,21 @@ const buildImage = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
46
46
|
registryconfig: options.registryConfig,
|
|
47
47
|
pull: options.pullPolicy.shouldPull() ? "true" : undefined,
|
|
48
48
|
};
|
|
49
|
-
|
|
49
|
+
yield new Promise((resolve) => {
|
|
50
50
|
dockerode
|
|
51
51
|
.buildImage(tarStream, buildImageOptions)
|
|
52
52
|
.then((stream) => (0, byline_1.default)(stream))
|
|
53
53
|
.then((stream) => {
|
|
54
54
|
stream.setEncoding("utf-8");
|
|
55
|
-
stream.on("data", (line) =>
|
|
55
|
+
stream.on("data", (line) => {
|
|
56
|
+
if (logger_1.buildLog.enabled()) {
|
|
57
|
+
logger_1.buildLog.trace(line, { imageName: options.imageName.toString() });
|
|
58
|
+
}
|
|
59
|
+
});
|
|
56
60
|
stream.on("end", () => resolve());
|
|
57
61
|
});
|
|
58
62
|
});
|
|
63
|
+
logger_1.log.info(`Built image "${options.imageName.toString()}" with context "${options.context}"`);
|
|
59
64
|
}
|
|
60
65
|
catch (err) {
|
|
61
66
|
logger_1.log.error(`Failed to build image: ${err}`);
|
|
@@ -13,22 +13,25 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.imageExists = void 0;
|
|
16
|
-
const logger_1 = require("../../../logger");
|
|
17
16
|
const async_lock_1 = __importDefault(require("async-lock"));
|
|
18
|
-
const list_images_1 = require("./list-images");
|
|
19
17
|
const existingImages = new Set();
|
|
20
18
|
const imageCheckLock = new async_lock_1.default();
|
|
21
19
|
const imageExists = (dockerode, imageName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
-
logger_1.log.debug(`Checking if image exists: ${imageName}`);
|
|
23
20
|
return imageCheckLock.acquire(imageName.toString(), () => __awaiter(void 0, void 0, void 0, function* () {
|
|
24
21
|
if (existingImages.has(imageName.toString())) {
|
|
25
22
|
return true;
|
|
26
23
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
existingImages.add(
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
try {
|
|
25
|
+
yield dockerode.getImage(imageName.toString()).inspect();
|
|
26
|
+
existingImages.add(imageName.toString());
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err instanceof Error && err.message.toLowerCase().includes("no such image")) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
throw err;
|
|
34
|
+
}
|
|
32
35
|
}));
|
|
33
36
|
});
|
|
34
37
|
exports.imageExists = imageExists;
|
|
@@ -24,13 +24,13 @@ const pullImage = (dockerode, indexServerAddress, options) => __awaiter(void 0,
|
|
|
24
24
|
return imagePullLock.acquire(options.imageName.toString(), () => __awaiter(void 0, void 0, void 0, function* () {
|
|
25
25
|
var _a;
|
|
26
26
|
if (!options.force && (yield (0, image_exists_1.imageExists)(dockerode, options.imageName))) {
|
|
27
|
-
logger_1.log.debug(`Not pulling image as it already exists
|
|
27
|
+
logger_1.log.debug(`Not pulling image "${options.imageName}" as it already exists`);
|
|
28
28
|
return;
|
|
29
29
|
}
|
|
30
|
-
logger_1.log.info(`Pulling image
|
|
30
|
+
logger_1.log.info(`Pulling image "${options.imageName}"...`);
|
|
31
31
|
const authconfig = yield (0, get_auth_config_1.getAuthConfig)((_a = options.imageName.registry) !== null && _a !== void 0 ? _a : indexServerAddress);
|
|
32
32
|
const stream = yield dockerode.pull(options.imageName.toString(), { authconfig });
|
|
33
|
-
yield new pull_stream_parser_1.PullStreamParser(options.imageName, logger_1.
|
|
33
|
+
yield new pull_stream_parser_1.PullStreamParser(options.imageName, logger_1.pullLog).consume(stream);
|
|
34
34
|
}));
|
|
35
35
|
}
|
|
36
36
|
catch (err) {
|
|
@@ -14,13 +14,14 @@ const logger_1 = require("../../../logger");
|
|
|
14
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
|
-
logger_1.log.info(`Connecting
|
|
17
|
+
logger_1.log.info(`Connecting to network "${options.networkId}"...`, { containerId: options.containerId });
|
|
18
18
|
const { dockerode } = yield (0, docker_client_1.dockerClient)();
|
|
19
19
|
const network = dockerode.getNetwork(options.networkId);
|
|
20
20
|
yield network.connect({ Container: options.containerId, EndpointConfig: { Aliases: options.networkAliases } });
|
|
21
|
+
logger_1.log.info(`Connected to network "${options.networkId}"...`, { containerId: options.containerId });
|
|
21
22
|
}
|
|
22
23
|
catch (err) {
|
|
23
|
-
logger_1.log.error(`Failed to connect
|
|
24
|
+
logger_1.log.error(`Failed to connect to network "${options.networkId}": ${err}`, { containerId: options.containerId });
|
|
24
25
|
throw err;
|
|
25
26
|
}
|
|
26
27
|
});
|
|
@@ -15,7 +15,7 @@ const docker_client_1 = require("../../docker-client");
|
|
|
15
15
|
const create_labels_1 = require("../create-labels");
|
|
16
16
|
const createNetwork = (options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
17
17
|
try {
|
|
18
|
-
logger_1.log.info(`Creating network ${options.name}
|
|
18
|
+
logger_1.log.info(`Creating network "${options.name}"...`);
|
|
19
19
|
const { dockerode } = yield (0, docker_client_1.dockerClient)();
|
|
20
20
|
const network = yield dockerode.createNetwork({
|
|
21
21
|
Name: options.name,
|
|
@@ -28,6 +28,7 @@ const createNetwork = (options) => __awaiter(void 0, void 0, void 0, function* (
|
|
|
28
28
|
Options: options.options,
|
|
29
29
|
Labels: Object.assign(Object.assign({}, options.labels), (0, create_labels_1.createLabels)(false)),
|
|
30
30
|
});
|
|
31
|
+
logger_1.log.info(`Created network "${options.name}"`);
|
|
31
32
|
return network.id;
|
|
32
33
|
}
|
|
33
34
|
catch (err) {
|
|
@@ -14,16 +14,17 @@ const logger_1 = require("../../../logger");
|
|
|
14
14
|
const docker_client_1 = require("../../docker-client");
|
|
15
15
|
const removeNetwork = (id) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
16
|
try {
|
|
17
|
-
logger_1.log.info(`Removing network ${id}
|
|
17
|
+
logger_1.log.info(`Removing network "${id}"...`);
|
|
18
18
|
const { dockerode } = yield (0, docker_client_1.dockerClient)();
|
|
19
19
|
const network = dockerode.getNetwork(id);
|
|
20
20
|
const { message } = yield network.remove();
|
|
21
21
|
if (message) {
|
|
22
22
|
logger_1.log.warn(message);
|
|
23
23
|
}
|
|
24
|
+
logger_1.log.info(`Removed network "${id}"`);
|
|
24
25
|
}
|
|
25
26
|
catch (err) {
|
|
26
|
-
logger_1.log.error(`Failed to remove network ${id}: ${err}`);
|
|
27
|
+
logger_1.log.error(`Failed to remove network "${id}": ${err}`);
|
|
27
28
|
throw err;
|
|
28
29
|
}
|
|
29
30
|
});
|
|
@@ -19,20 +19,20 @@ const stream_utils_1 = require("../../stream-utils");
|
|
|
19
19
|
const runInContainer = (dockerode, indexServerAddress, image, command) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
20
|
try {
|
|
21
21
|
yield (0, pull_image_1.pullImage)(dockerode, indexServerAddress, { imageName: docker_image_name_1.DockerImageName.fromString(image), force: false });
|
|
22
|
-
logger_1.log.debug(`Creating container: ${image} with command
|
|
22
|
+
logger_1.log.debug(`Creating container: ${image} with command "${command.join(" ")}"...`);
|
|
23
23
|
const container = yield dockerode.createContainer({ Image: image, Cmd: command });
|
|
24
|
-
logger_1.log.debug(`Attaching to container:
|
|
24
|
+
logger_1.log.debug(`Attaching to container...`, { containerId: container.id });
|
|
25
25
|
const stream = yield (0, attach_container_1.attachContainer)(dockerode, container);
|
|
26
|
-
logger_1.log.debug(`Starting container:
|
|
26
|
+
logger_1.log.debug(`Starting container...`, { containerId: container.id });
|
|
27
27
|
yield (0, start_container_1.startContainer)(container);
|
|
28
|
-
logger_1.log.debug(`Waiting for container output:
|
|
28
|
+
logger_1.log.debug(`Waiting for container output...`, { containerId: container.id });
|
|
29
29
|
const output = yield (0, stream_utils_1.streamToString)(stream, { trim: true });
|
|
30
|
-
logger_1.log.debug(`Removing container:
|
|
30
|
+
logger_1.log.debug(`Removing container...`, { containerId: container.id });
|
|
31
31
|
yield container.remove({ force: true, v: true });
|
|
32
32
|
return output.length === 0 ? undefined : output;
|
|
33
33
|
}
|
|
34
34
|
catch (err) {
|
|
35
|
-
logger_1.log.error(`Failed to run command
|
|
35
|
+
logger_1.log.error(`Failed to run command "${command.join(" ")}" in container: "${err}"`);
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
38
|
});
|
|
@@ -11,53 +11,14 @@ class PullStreamParser {
|
|
|
11
11
|
this.logger = logger;
|
|
12
12
|
}
|
|
13
13
|
consume(stream) {
|
|
14
|
-
const messagesById = new Map();
|
|
15
|
-
const statusesById = new Map();
|
|
16
14
|
return new Promise((resolve) => {
|
|
17
15
|
(0, byline_1.default)(stream).on("data", (line) => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const { id, status } = json;
|
|
21
|
-
const prefix = id
|
|
22
|
-
? `Pulling ${this.dockerImageName.toString()} - ${id}`
|
|
23
|
-
: `Pulling ${this.dockerImageName.toString()}`;
|
|
24
|
-
if (status === "Downloading") {
|
|
25
|
-
const { current, total } = json.progressDetail;
|
|
26
|
-
const percentage = Math.round(100 * (current / total));
|
|
27
|
-
const message = `${prefix} - ${json.status} ${percentage}%`;
|
|
28
|
-
const messages = this.getOrElse(messagesById, id, new Set());
|
|
29
|
-
if (!messages.has(message)) {
|
|
30
|
-
messages.add(message);
|
|
31
|
-
this.logger.trace(message);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
const statuses = this.getOrElse(statusesById, id, new Set());
|
|
36
|
-
if (!statuses.has(status)) {
|
|
37
|
-
statuses.add(status);
|
|
38
|
-
const message = `${prefix} - ${json.status}`;
|
|
39
|
-
const messages = this.getOrElse(messagesById, id, new Set());
|
|
40
|
-
if (!messages.has(message)) {
|
|
41
|
-
messages.add(message);
|
|
42
|
-
this.logger.trace(message);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
catch (_a) {
|
|
48
|
-
this.logger.warn(`Unexpected message format: ${line}`);
|
|
16
|
+
if (this.logger.enabled()) {
|
|
17
|
+
this.logger.trace(line, { imageName: this.dockerImageName.toString() });
|
|
49
18
|
}
|
|
50
19
|
});
|
|
51
20
|
stream.on("end", resolve);
|
|
52
21
|
});
|
|
53
22
|
}
|
|
54
|
-
getOrElse(map, key, orElse) {
|
|
55
|
-
const value = map.get(key);
|
|
56
|
-
if (value === undefined) {
|
|
57
|
-
map.set(key, orElse);
|
|
58
|
-
return orElse;
|
|
59
|
-
}
|
|
60
|
-
return value;
|
|
61
|
-
}
|
|
62
23
|
}
|
|
63
24
|
exports.PullStreamParser = PullStreamParser;
|