diff --git a/package-lock.json b/package-lock.json index 0bd09fca..f381af50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "testcontainers", - "version": "8.13.1", + "version": "8.13.1-beta.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "testcontainers", - "version": "8.12.0", + "version": "8.13.1-beta.5", "license": "MIT", "dependencies": { "@balena/dockerignore": "^1.0.2", diff --git a/package.json b/package.json index 9b1408e6..c33740c4 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "testcontainers", "author": "Cristian Greco", - "version": "8.13.1", + "version": "8.13.1-beta.5", "main": "dist/index", "types": "dist/index", "keywords": [ diff --git a/src/docker/docker-client.ts b/src/docker/docker-client.ts index a96074da..158cb588 100644 --- a/src/docker/docker-client.ts +++ b/src/docker/docker-client.ts @@ -28,7 +28,7 @@ const getDockerClient = async (): Promise => { if (await isDockerDaemonReachable(dockerode)) { const host = await resolveHost(dockerode, uri); log.info(`Using Docker client strategy: ${strategy.getName()}, Docker host: ${host}`); - logSystemDiagnostics(); + logSystemDiagnostics(dockerode); return { host, dockerode }; } else { log.warn(`Docker client strategy ${strategy.getName()} is not reachable`); @@ -158,12 +158,15 @@ const resolveHost = async (dockerode: Dockerode, uri: string): Promise = }; const findGateway = async (dockerode: Dockerode): Promise => { + log.debug(`Checking gateway for Docker host`); const inspectResult: NetworkInspectInfo = await dockerode.getNetwork("bridge").inspect(); return inspectResult?.IPAM?.Config?.find((config) => config.Gateway !== undefined)?.Gateway; }; -const findDefaultGateway = async (dockerode: Dockerode): Promise => - runInContainer(dockerode, "alpine:3.14", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]); +const findDefaultGateway = async (dockerode: Dockerode): Promise => { + log.debug(`Checking default gateway for Docker host`); + return runInContainer(dockerode, "alpine:3.14", ["sh", "-c", "ip route|awk '/default/ { print $3 }'"]); +}; const isInContainer = () => existsSync("/.dockerenv"); diff --git a/src/docker/functions/container/attach-container.ts b/src/docker/functions/container/attach-container.ts index 8de1c8c0..6fa64b52 100644 --- a/src/docker/functions/container/attach-container.ts +++ b/src/docker/functions/container/attach-container.ts @@ -3,10 +3,10 @@ import Dockerode from "dockerode"; import { demuxStream } from "../demux-stream"; import { log } from "../../../logger"; -export const attachContainer = async (container: Dockerode.Container): Promise => { +export const attachContainer = async (dockerode: Dockerode, container: Dockerode.Container): Promise => { try { const stream = (await container.attach({ stream: true, stdout: true, stderr: true })) as NodeJS.ReadableStream; - return demuxStream(stream as Readable); + return demuxStream(dockerode, stream as Readable); } catch (err) { log.error(`Failed to attach to container ${container.id}: ${err}`); throw err; diff --git a/src/docker/functions/container/container-logs.ts b/src/docker/functions/container/container-logs.ts index 7d5a67c1..4832eb04 100644 --- a/src/docker/functions/container/container-logs.ts +++ b/src/docker/functions/container/container-logs.ts @@ -3,6 +3,7 @@ import { log } from "../../../logger"; import Dockerode from "dockerode"; import { demuxStream } from "../demux-stream"; import { Readable } from "stream"; +import { dockerClient } from "../../docker-client"; export const containerLogs = async (container: Dockerode.Container): Promise => { try { @@ -15,7 +16,7 @@ export const containerLogs = async (container: Dockerode.Container): Promise => { +export const demuxStream = async (dockerode: Dockerode, stream: Readable): Promise => { try { const demuxedStream = new PassThrough({ autoDestroy: true, encoding: "utf-8" }); - const { dockerode } = await dockerClient(); dockerode.modem.demuxStream(stream, demuxedStream, demuxedStream); stream.on("end", () => demuxedStream.end()); demuxedStream.on("close", () => { diff --git a/src/docker/functions/get-info.ts b/src/docker/functions/get-info.ts index 92d29bca..094905e0 100644 --- a/src/docker/functions/get-info.ts +++ b/src/docker/functions/get-info.ts @@ -1,4 +1,4 @@ -import { dockerClient } from "../docker-client"; +import Dockerode from "dockerode"; type DockerInfo = { serverVersion: number; @@ -9,8 +9,7 @@ type DockerInfo = { memory: number; }; -export const getDockerInfo = async (): Promise => { - const { dockerode } = await dockerClient(); +export const getDockerInfo = async (dockerode: Dockerode): Promise => { const info = await dockerode.info(); return { diff --git a/src/docker/functions/image/image-exists.ts b/src/docker/functions/image/image-exists.ts index d059b020..78c24061 100644 --- a/src/docker/functions/image/image-exists.ts +++ b/src/docker/functions/image/image-exists.ts @@ -1,6 +1,9 @@ import { DockerImageName } from "../../../docker-image-name"; import { listImages } from "./list-images"; +import { log } from "../../../logger"; +import Dockerode from "dockerode"; -export const imageExists = async (imageName: DockerImageName): Promise => { - return (await listImages()).some((image) => image.equals(imageName)); +export const imageExists = async (dockerode: Dockerode, imageName: DockerImageName): Promise => { + log.debug(`Checking if image exists: ${imageName}`); + return (await listImages(dockerode)).some((image) => image.equals(imageName)); }; diff --git a/src/docker/functions/image/list-images.ts b/src/docker/functions/image/list-images.ts index 77aca4bf..94596989 100644 --- a/src/docker/functions/image/list-images.ts +++ b/src/docker/functions/image/list-images.ts @@ -1,13 +1,10 @@ import { DockerImageName } from "../../../docker-image-name"; -import { dockerClient } from "../../docker-client"; import Dockerode from "dockerode"; import { log } from "../../../logger"; -export const listImages = async (): Promise => { +export const listImages = async (dockerode: Dockerode): Promise => { try { - const { dockerode } = await dockerClient(); const images = await dockerode.listImages(); - return images.reduce((dockerImageNames: DockerImageName[], image) => { if (isDanglingImage(image)) { return dockerImageNames; diff --git a/src/docker/functions/image/pull-image.ts b/src/docker/functions/image/pull-image.ts index 154a22f0..a8c9a5fa 100644 --- a/src/docker/functions/image/pull-image.ts +++ b/src/docker/functions/image/pull-image.ts @@ -4,6 +4,7 @@ import { PullStreamParser } from "../../pull-stream-parser"; import { dockerClient } from "../../docker-client"; import { AuthConfig } from "../../types"; import { imageExists } from "./image-exists"; +import Dockerode from "dockerode"; export type PullImageOptions = { imageName: DockerImageName; @@ -11,15 +12,14 @@ export type PullImageOptions = { authConfig?: AuthConfig; }; -export const pullImage = async (options: PullImageOptions): Promise => { +export const pullImage = async (dockerode: Dockerode, options: PullImageOptions): Promise => { try { - if ((await imageExists(options.imageName)) && !options.force) { + if ((await imageExists(dockerode, options.imageName)) && !options.force) { log.debug(`Not pulling image as it already exists: ${options.imageName}`); return; } log.info(`Pulling image: ${options.imageName}`); - const { dockerode } = await dockerClient(); const stream = await dockerode.pull(options.imageName.toString(), { authconfig: options.authConfig }); await new PullStreamParser(options.imageName, log).consume(stream); diff --git a/src/docker/functions/run-in-container.ts b/src/docker/functions/run-in-container.ts index 2b63f70f..44978096 100644 --- a/src/docker/functions/run-in-container.ts +++ b/src/docker/functions/run-in-container.ts @@ -15,12 +15,12 @@ export const runInContainer = async ( try { const imageName = DockerImageName.fromString(image); - await pullImage({ imageName, force: false }); + await pullImage(dockerode, { imageName, force: false }); log.debug(`Creating container: ${image} with command: ${command.join(" ")}`); const container = await dockerode.createContainer({ Image: image, Cmd: command, HostConfig: { AutoRemove: true } }); log.debug(`Attaching to container: ${container.id}`); - const stream = await attachContainer(container); + const stream = await attachContainer(dockerode, container); const promise = new Promise((resolve) => { const interval = setInterval(async () => { diff --git a/src/generic-container/generic-container-builder.ts b/src/generic-container/generic-container-builder.ts index 75c8d415..af8970ed 100644 --- a/src/generic-container/generic-container-builder.ts +++ b/src/generic-container/generic-container-builder.ts @@ -10,6 +10,7 @@ import { buildImage } from "../docker/functions/image/build-image"; import { imageExists } from "../docker/functions/image/image-exists"; import { getAuthConfig } from "../registry-auth-locator"; import { GenericContainer } from "./generic-container"; +import { dockerClient } from "../docker/docker-client"; export class GenericContainerBuilder { private buildArgs: BuildArgs = {}; @@ -51,7 +52,7 @@ export class GenericContainerBuilder { }); const container = new GenericContainer(imageName.toString()); - if (!(await imageExists(imageName))) { + if (!(await imageExists((await dockerClient()).dockerode, imageName))) { throw new Error("Failed to build image"); } diff --git a/src/generic-container/generic-container.ts b/src/generic-container/generic-container.ts index 63e3fe46..d858dc92 100644 --- a/src/generic-container/generic-container.ts +++ b/src/generic-container/generic-container.ts @@ -81,7 +81,7 @@ export class GenericContainer implements TestContainer { protected preStart?(): Promise; public async start(): Promise { - await pullImage({ + await pullImage((await dockerClient()).dockerode, { imageName: this.imageName, force: this.pullPolicy.shouldPull(), authConfig: await getAuthConfig(this.imageName.registry), diff --git a/src/log-system-diagnostics.ts b/src/log-system-diagnostics.ts index 9aa302c4..e8638820 100644 --- a/src/log-system-diagnostics.ts +++ b/src/log-system-diagnostics.ts @@ -1,11 +1,14 @@ import { log } from "./logger"; import { version as dockerComposeVersion } from "./docker-compose/docker-compose"; import { getDockerInfo } from "./docker/functions/get-info"; +import Dockerode from "dockerode"; + +export const logSystemDiagnostics = async (dockerode: Dockerode): Promise => { + log.debug("Fetching system diagnostics"); -export const logSystemDiagnostics = async (): Promise => { const info = { node: getNodeInfo(), - docker: await getDockerInfo(), + docker: await getDockerInfo(dockerode), dockerCompose: await getDockerComposeInfo(), }; diff --git a/src/reaper.test.ts b/src/reaper.test.ts index 7f5f1936..2e5b8e76 100644 --- a/src/reaper.test.ts +++ b/src/reaper.test.ts @@ -7,6 +7,7 @@ import waitForExpect from "wait-for-expect"; import { listImages } from "./docker/functions/image/list-images"; import { DockerImageName } from "./docker-image-name"; import { DockerComposeEnvironment } from "./docker-compose-environment/docker-compose-environment"; +import { dockerClient } from "./docker/docker-client"; const fixtures = path.resolve(__dirname, "..", "fixtures"); @@ -67,9 +68,10 @@ describe("Reaper", () => { const reaperContainerId = await getReaperContainerId(); await stopReaper(); - expect(await listImages()).toContainEqual(DockerImageName.fromString(imageId)); + const { dockerode } = await dockerClient(); + expect(await listImages(dockerode)).toContainEqual(DockerImageName.fromString(imageId)); await waitForExpect(async () => { - expect(await listImages()).not.toContainEqual(DockerImageName.fromString(imageId)); + expect(await listImages(dockerode)).not.toContainEqual(DockerImageName.fromString(imageId)); expect(await getContainerIds()).not.toContain(reaperContainerId); }, 30_000); });