-
-
Notifications
You must be signed in to change notification settings - Fork 182
/
generic-container-builder.ts
107 lines (91 loc) · 3.39 KB
/
generic-container-builder.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
import { AuthConfig, BuildArgs, RegistryConfig } from "../types";
import path from "path";
import { GenericContainer } from "./generic-container";
import { ImagePullPolicy, PullPolicy } from "../utils/pull-policy";
import { log, RandomUuid, Uuid } from "../common";
import { getAuthConfig, getContainerRuntimeClient, ImageName } from "../container-runtime";
import { getReaper } from "../reaper/reaper";
import { getDockerfileImages } from "../utils/dockerfile-parser";
import { createLabels, LABEL_TESTCONTAINERS_SESSION_ID } from "../utils/labels";
export type BuildOptions = {
deleteOnExit: boolean;
};
export class GenericContainerBuilder {
private buildArgs: BuildArgs = {};
private pullPolicy: ImagePullPolicy = PullPolicy.defaultPolicy();
private cache = true;
private target?: string;
constructor(
private readonly context: string,
private readonly dockerfileName: string,
private readonly uuid: Uuid = new RandomUuid()
) {}
public withBuildArgs(buildArgs: BuildArgs): GenericContainerBuilder {
this.buildArgs = buildArgs;
return this;
}
public withPullPolicy(pullPolicy: ImagePullPolicy): this {
this.pullPolicy = pullPolicy;
return this;
}
public withCache(cache: boolean): this {
this.cache = cache;
return this;
}
public withTarget(target: string): this {
this.target = target;
return this;
}
public async build(
image = `localhost/${this.uuid.nextUuid()}:${this.uuid.nextUuid()}`,
options: BuildOptions = { deleteOnExit: true }
): Promise<GenericContainer> {
const client = await getContainerRuntimeClient();
const reaper = await getReaper(client);
const imageName = ImageName.fromString(image);
const dockerfile = path.resolve(this.context, this.dockerfileName);
const imageNames = await getDockerfileImages(dockerfile, this.buildArgs);
const registryConfig = await this.getRegistryConfig(client.info.containerRuntime.indexServerAddress, imageNames);
const labels = createLabels();
if (options.deleteOnExit) {
labels[LABEL_TESTCONTAINERS_SESSION_ID] = reaper.sessionId;
}
log.info(`Building Dockerfile "${dockerfile}" as image "${imageName.string}"...`);
await client.image.build(this.context, {
t: imageName.string,
dockerfile: this.dockerfileName,
buildargs: this.buildArgs,
pull: this.pullPolicy ? "true" : undefined,
nocache: !this.cache,
registryconfig: registryConfig,
labels,
target: this.target,
});
const container = new GenericContainer(imageName.string);
if (!(await client.image.exists(imageName))) {
throw new Error("Failed to build image");
}
return Promise.resolve(container);
}
private async getRegistryConfig(indexServerAddress: string, imageNames: ImageName[]): Promise<RegistryConfig> {
const authConfigs: AuthConfig[] = [];
await Promise.all(
imageNames.map(async (imageName) => {
const authConfig = await getAuthConfig(imageName.registry ?? indexServerAddress);
if (authConfig !== undefined) {
authConfigs.push(authConfig);
}
})
);
return authConfigs
.map((authConfig) => {
return {
[authConfig.registryAddress]: {
username: authConfig.username,
password: authConfig.password,
},
};
})
.reduce((prev, next) => ({ ...prev, ...next }), {} as RegistryConfig);
}
}