build-strap 3.0.0-dev.42 → 4.0.0-dev.2
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/LICENSE +1 -1
- package/README.md +3 -34
- package/ant.d.ts +19 -0
- package/ant.js +12 -37
- package/cert.d.ts +12 -0
- package/cert.js +89 -151
- package/clean.d.ts +4 -0
- package/clean.js +7 -16
- package/copy.d.ts +7 -0
- package/copy.js +49 -76
- package/cp.d.ts +17 -0
- package/cp.js +85 -170
- package/docker.container.d.ts +73 -0
- package/docker.container.js +219 -362
- package/docker.d.ts +68 -0
- package/docker.js +167 -347
- package/docker.network.d.ts +42 -0
- package/docker.network.js +69 -144
- package/docker.volume.d.ts +26 -0
- package/docker.volume.js +52 -126
- package/dockerCleanup.d.ts +38 -0
- package/dockerCleanup.js +66 -141
- package/dockerCompose.d.ts +154 -0
- package/dockerCompose.js +400 -727
- package/fs.d.ts +5 -0
- package/fs.js +38 -95
- package/git.d.ts +9 -0
- package/git.js +19 -30
- package/index.d.ts +20 -0
- package/index.js +20 -27
- package/maps.d.ts +33 -0
- package/maps.js +16 -87
- package/npm.d.ts +34 -0
- package/npm.js +97 -138
- package/package.json +23 -19
- package/pkg.d.ts +39 -0
- package/pkg.js +26 -74
- package/publish.d.ts +27 -0
- package/publish.js +52 -140
- package/run.d.ts +13 -0
- package/run.js +39 -85
- package/tgz.d.ts +13 -0
- package/tgz.js +61 -96
- package/version.d.ts +34 -0
- package/version.js +86 -127
- package/yarn.d.ts +26 -0
- package/yarn.js +70 -119
- package/ant.js.flow +0 -42
- package/artifactory.js +0 -617
- package/artifactory.js.flow +0 -616
- package/cert.conf +0 -20
- package/cert.js.flow +0 -152
- package/clean.js.flow +0 -19
- package/copy.js.flow +0 -79
- package/cp.js.flow +0 -172
- package/docker.container.js.flow +0 -389
- package/docker.js.flow +0 -367
- package/docker.network.js.flow +0 -159
- package/docker.volume.js.flow +0 -136
- package/dockerCleanup.js.flow +0 -151
- package/dockerCompose.js.flow +0 -765
- package/flow.js +0 -21
- package/flow.js.flow +0 -20
- package/fs.js.flow +0 -96
- package/git.js.flow +0 -34
- package/hg.js +0 -35
- package/hg.js.flow +0 -34
- package/index.js.flow +0 -26
- package/inline-resources.js +0 -158
- package/inline-resources.js.flow +0 -157
- package/maps.js.flow +0 -111
- package/npm.js.flow +0 -144
- package/pkg.js.flow +0 -80
- package/publish.js.flow +0 -144
- package/run.js.flow +0 -89
- package/src/ant.js +0 -42
- package/src/artifactory.js +0 -616
- package/src/cert.conf +0 -20
- package/src/cert.js +0 -152
- package/src/clean.js +0 -19
- package/src/copy.js +0 -79
- package/src/cp.js +0 -172
- package/src/docker.container.js +0 -389
- package/src/docker.js +0 -367
- package/src/docker.network.js +0 -159
- package/src/docker.volume.js +0 -136
- package/src/dockerCleanup.js +0 -151
- package/src/dockerCompose.js +0 -765
- package/src/flow.js +0 -20
- package/src/fs.js +0 -96
- package/src/git.js +0 -34
- package/src/hg.js +0 -34
- package/src/index.js +0 -26
- package/src/inline-resources.js +0 -157
- package/src/maps.js +0 -111
- package/src/npm.js +0 -144
- package/src/pkg.js +0 -80
- package/src/publish.js +0 -144
- package/src/run.js +0 -89
- package/src/test.js +0 -55
- package/src/tgz.js +0 -101
- package/src/version.js +0 -141
- package/src/yarn.js +0 -123
- package/test.js +0 -56
- package/test.js.flow +0 -55
- package/tgz.js.flow +0 -101
- package/version.js.flow +0 -141
- package/yarn.js.flow +0 -123
package/dockerCompose.js.flow
DELETED
|
@@ -1,765 +0,0 @@
|
|
|
1
|
-
// @flow
|
|
2
|
-
import fs from 'fs-extra';
|
|
3
|
-
import yaml from 'js-yaml';
|
|
4
|
-
import path from 'path';
|
|
5
|
-
import getPort from 'get-port';
|
|
6
|
-
import { keys, entries, mapValuesAsync, type MapObj } from './maps';
|
|
7
|
-
|
|
8
|
-
import { buildLog } from './run';
|
|
9
|
-
import { dockerPull } from './docker';
|
|
10
|
-
import {
|
|
11
|
-
dockerContainerFind,
|
|
12
|
-
dockerContainerRunDaemon,
|
|
13
|
-
type DockerContainer,
|
|
14
|
-
} from './docker.container';
|
|
15
|
-
import {
|
|
16
|
-
dockerNetworkDelete,
|
|
17
|
-
dockerNetworkCreate,
|
|
18
|
-
type DockerNetworkCreateOptions,
|
|
19
|
-
type DockerNetwork,
|
|
20
|
-
} from './docker.network';
|
|
21
|
-
import {
|
|
22
|
-
dockerVolumeCreate,
|
|
23
|
-
dockerVolumeRm,
|
|
24
|
-
type DockerVolume,
|
|
25
|
-
} from './docker.volume';
|
|
26
|
-
|
|
27
|
-
export type DockerComposeResourceTracker = {
|
|
28
|
-
services: Map<string, DockerComposeService>,
|
|
29
|
-
networks: Map<string, DockerNetwork>,
|
|
30
|
-
containers: Map<string, DockerContainer>,
|
|
31
|
-
volumes: Map<string, DockerVolume>,
|
|
32
|
-
cleaning: ?Promise<void>,
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
export const dockerComposeCreateResourceTracker = (): DockerComposeResourceTracker => ({
|
|
36
|
-
networks: new Map(),
|
|
37
|
-
services: new Map(),
|
|
38
|
-
containers: new Map(),
|
|
39
|
-
volumes: new Map(),
|
|
40
|
-
cleaning: null,
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
const defaultTracker = dockerComposeCreateResourceTracker();
|
|
44
|
-
|
|
45
|
-
type DockerComposeEnvDef = string[] | { [string]: string };
|
|
46
|
-
|
|
47
|
-
type DockerComposeULimitDef = number | { soft: number, hard: number };
|
|
48
|
-
|
|
49
|
-
type DockerComposeULimitsDef = {
|
|
50
|
-
[string]: DockerComposeULimitDef,
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
type DockerComposeServiceDef = {
|
|
54
|
-
container_name?: string,
|
|
55
|
-
image?: string,
|
|
56
|
-
ports?: string[],
|
|
57
|
-
volumes?: string[],
|
|
58
|
-
command?: string[],
|
|
59
|
-
networks?: string[],
|
|
60
|
-
environment?: DockerComposeEnvDef,
|
|
61
|
-
links?: string[],
|
|
62
|
-
ulimits?: DockerComposeULimitsDef,
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
type DockerComposeVolumeDef = {
|
|
66
|
-
name?: string,
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
type DockerComposeNetworkDef = {
|
|
70
|
-
...DockerNetworkCreateOptions,
|
|
71
|
-
name?: string,
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
type DockerCompose = {
|
|
75
|
-
version: string,
|
|
76
|
-
services?: {
|
|
77
|
-
[string]: DockerComposeServiceDef,
|
|
78
|
-
},
|
|
79
|
-
volumes?: {
|
|
80
|
-
[string]: DockerComposeVolumeDef,
|
|
81
|
-
},
|
|
82
|
-
networks?: {
|
|
83
|
-
[string]: DockerComposeNetworkDef,
|
|
84
|
-
},
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Parse a docker-compose.yml file into a pojo representation
|
|
89
|
-
* @param {string} filePath Path to the docker-compose.yml file
|
|
90
|
-
*/
|
|
91
|
-
export const dockerComposeParse = async (
|
|
92
|
-
filePath?: string = './docker-compose.yml',
|
|
93
|
-
): Promise<DockerCompose> => (yaml.load(await fs.readFile(filePath)): any);
|
|
94
|
-
|
|
95
|
-
let dc: ?DockerCompose = null;
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get the main docker-compose.yml from the root of the repo
|
|
99
|
-
* @param {boolean} force Force reload from file
|
|
100
|
-
*/
|
|
101
|
-
export const dockerComposeGetMain = async (
|
|
102
|
-
force?: boolean = false,
|
|
103
|
-
): Promise<DockerCompose> => {
|
|
104
|
-
if (force || !dc) {
|
|
105
|
-
dc = await dockerComposeParse();
|
|
106
|
-
}
|
|
107
|
-
return dc;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
// Function that handles passed dockerCompose as either a file path or `DockerCompose` object.
|
|
111
|
-
// If not passed, defaults to the main docker-compose.yml from the root of the repo
|
|
112
|
-
const dockerComposeResolve = async (
|
|
113
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
114
|
-
force?: boolean,
|
|
115
|
-
): Promise<DockerCompose> =>
|
|
116
|
-
typeof dockerCompose === 'string'
|
|
117
|
-
? dockerComposeParse(dockerCompose)
|
|
118
|
-
: dockerCompose || dockerComposeGetMain(force);
|
|
119
|
-
|
|
120
|
-
// Determines an unnamed resource's name from the dirname combined with the key
|
|
121
|
-
const prefixName = (name: string) => `${path.basename(__dirname)}_${name}`;
|
|
122
|
-
|
|
123
|
-
const getServiceDef = async (
|
|
124
|
-
name: string,
|
|
125
|
-
force?: boolean,
|
|
126
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
127
|
-
): Promise<?DockerComposeServiceDef> =>
|
|
128
|
-
(await dockerComposeResolve(dockerCompose, force)).services?.[name] || null;
|
|
129
|
-
|
|
130
|
-
type PortMap = {
|
|
131
|
-
local: ?number,
|
|
132
|
-
localDefault: number,
|
|
133
|
-
docker: number,
|
|
134
|
-
};
|
|
135
|
-
|
|
136
|
-
type UrlMap = {
|
|
137
|
-
local: ?string,
|
|
138
|
-
docker: ?string,
|
|
139
|
-
};
|
|
140
|
-
|
|
141
|
-
type ParsedPortInfo = {
|
|
142
|
-
runArgs: string[],
|
|
143
|
-
ports: PortMap[],
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
const parsePorts = async (
|
|
147
|
-
portsCfg?: string[] = [],
|
|
148
|
-
avoidConflicts?: boolean = true,
|
|
149
|
-
mapLocal?: boolean = true,
|
|
150
|
-
host?: string = '0.0.0.0',
|
|
151
|
-
): Promise<ParsedPortInfo> => {
|
|
152
|
-
const ports: PortMap[] = [];
|
|
153
|
-
const runArgs = await portsCfg.reduce(async (args, portStr) => {
|
|
154
|
-
const [lp, dp] = portStr.split(':');
|
|
155
|
-
const localDefault = parseInt(lp, 10);
|
|
156
|
-
const docker = parseInt(dp, 10);
|
|
157
|
-
const local = mapLocal
|
|
158
|
-
? avoidConflicts
|
|
159
|
-
? await getPort({ port: localDefault, host })
|
|
160
|
-
: localDefault
|
|
161
|
-
: null;
|
|
162
|
-
ports.push({ local, localDefault, docker });
|
|
163
|
-
return local ? [...(await args), '-p', `${local}:${docker}`] : args;
|
|
164
|
-
}, []);
|
|
165
|
-
return { runArgs, ports };
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
const parseEnv = (env?: DockerComposeEnvDef = []): string[] =>
|
|
169
|
-
Array.isArray(env)
|
|
170
|
-
? env.flatMap((e) => ['-e', e])
|
|
171
|
-
: entries(env).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
|
|
172
|
-
|
|
173
|
-
const parseULimits = (ul?: DockerComposeULimitsDef = {}): string[] =>
|
|
174
|
-
entries(ul).flatMap(([k, v]) => [
|
|
175
|
-
'--ulimit',
|
|
176
|
-
`${k}=${
|
|
177
|
-
typeof v === 'number' ? v : `${v.soft}${v.hard ? `:${v.hard}` : ''}`
|
|
178
|
-
}`,
|
|
179
|
-
]);
|
|
180
|
-
|
|
181
|
-
type ParsedVolumeInfo = {
|
|
182
|
-
runArgs: string[],
|
|
183
|
-
volumes: string[],
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
const parseVolumes = async (
|
|
187
|
-
volCfg?: string[] = [],
|
|
188
|
-
nameSuffix?: string = '',
|
|
189
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
190
|
-
): Promise<ParsedVolumeInfo> => {
|
|
191
|
-
const { volumes: volMap } = await dockerComposeResolve(dockerCompose);
|
|
192
|
-
const volumes = [];
|
|
193
|
-
const runArgs: string[] = volCfg
|
|
194
|
-
.map((v) => {
|
|
195
|
-
const [src, ...rest] = v.split(':');
|
|
196
|
-
const name = volMap?.[src]
|
|
197
|
-
? `${volMap[src].name || prefixName(src)}${nameSuffix}`
|
|
198
|
-
: null;
|
|
199
|
-
if (name) {
|
|
200
|
-
volumes.push(name);
|
|
201
|
-
}
|
|
202
|
-
const realSrc = name || path.resolve(src);
|
|
203
|
-
return [realSrc, ...rest].join(':');
|
|
204
|
-
})
|
|
205
|
-
.flatMap((v) => ['-v', v]);
|
|
206
|
-
return { runArgs, volumes };
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
type ParsedNetworkInfo = {
|
|
210
|
-
runArgs: string[],
|
|
211
|
-
networks: string[],
|
|
212
|
-
};
|
|
213
|
-
|
|
214
|
-
const parseNetworks = async (
|
|
215
|
-
netCfg?: string[] = [],
|
|
216
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
217
|
-
): Promise<ParsedNetworkInfo> => {
|
|
218
|
-
const { networks: netMap } = await dockerComposeResolve(dockerCompose);
|
|
219
|
-
const networks = netCfg.map((n) => netMap?.[n].name || prefixName(n));
|
|
220
|
-
return {
|
|
221
|
-
networks,
|
|
222
|
-
runArgs: (networks.flatMap((n) => ['--network', n]): string[]),
|
|
223
|
-
};
|
|
224
|
-
};
|
|
225
|
-
|
|
226
|
-
export const dockerComposeCreateNetworks = async (
|
|
227
|
-
names?: ?(string[]),
|
|
228
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
229
|
-
tracker?: DockerComposeResourceTracker = defaultTracker,
|
|
230
|
-
) => {
|
|
231
|
-
const { networks = {} } = await dockerComposeResolve(dockerCompose);
|
|
232
|
-
await Promise.all(
|
|
233
|
-
entries(networks).map(async ([key, val]) => {
|
|
234
|
-
const name = val?.name || prefixName(key);
|
|
235
|
-
if (!names || names.includes(name)) {
|
|
236
|
-
const network = await dockerNetworkCreate(name, (val || {}: any));
|
|
237
|
-
if (network) {
|
|
238
|
-
tracker.networks.set(name, network);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}),
|
|
242
|
-
);
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
export const dockerComposeCreateVolumes = async (
|
|
246
|
-
names?: string[],
|
|
247
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
248
|
-
tracker?: DockerComposeResourceTracker = defaultTracker,
|
|
249
|
-
) => {
|
|
250
|
-
const { volumes = {} } = await dockerComposeResolve(dockerCompose);
|
|
251
|
-
await Promise.all(
|
|
252
|
-
entries(volumes).map(async ([key, val]) => {
|
|
253
|
-
const name = val?.name || prefixName(key);
|
|
254
|
-
if (!names || names.includes(name)) {
|
|
255
|
-
const volume = await dockerVolumeCreate(name, (val || {}: any));
|
|
256
|
-
if (volume) {
|
|
257
|
-
tracker.volumes.set(name, volume);
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}),
|
|
261
|
-
);
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
type HealthCheckFn = (UpResult) => Promise<void>;
|
|
265
|
-
|
|
266
|
-
type UpOptions = {
|
|
267
|
-
healthCheck?: HealthCheckFn,
|
|
268
|
-
avoidConflicts?: boolean,
|
|
269
|
-
mapVolumes?: boolean,
|
|
270
|
-
mapPorts?: boolean,
|
|
271
|
-
cmd?: string[],
|
|
272
|
-
tracker?: DockerComposeResourceTracker,
|
|
273
|
-
};
|
|
274
|
-
|
|
275
|
-
type ServiceNameInfo = {
|
|
276
|
-
name: string,
|
|
277
|
-
aliases: string[],
|
|
278
|
-
suffix: string,
|
|
279
|
-
};
|
|
280
|
-
|
|
281
|
-
type UpResult = {|
|
|
282
|
-
service: DockerComposeService,
|
|
283
|
-
container: DockerContainer,
|
|
284
|
-
containerName: string,
|
|
285
|
-
aliases: string[],
|
|
286
|
-
ports: PortMap[],
|
|
287
|
-
urls: UrlMap[],
|
|
288
|
-
volumes: string[],
|
|
289
|
-
|};
|
|
290
|
-
|
|
291
|
-
export class DockerComposeService {
|
|
292
|
-
#name: string;
|
|
293
|
-
#svcDef: DockerComposeServiceDef;
|
|
294
|
-
#dockerCompose: ?(DockerCompose | string);
|
|
295
|
-
#tracker: DockerComposeResourceTracker = dockerComposeCreateResourceTracker();
|
|
296
|
-
|
|
297
|
-
// lazily computed
|
|
298
|
-
#parsedPorts: ?ParsedPortInfo = null;
|
|
299
|
-
#parsedNetworks: ?ParsedNetworkInfo = null;
|
|
300
|
-
#parsedVolumes: ?ParsedVolumeInfo = null;
|
|
301
|
-
#baseRunArgs: ?(string[]) = null;
|
|
302
|
-
|
|
303
|
-
constructor(
|
|
304
|
-
name: string,
|
|
305
|
-
serviceDef: DockerComposeServiceDef,
|
|
306
|
-
dockerCompose?: ?(DockerCompose | string),
|
|
307
|
-
) {
|
|
308
|
-
this.#name = name;
|
|
309
|
-
this.#svcDef = serviceDef;
|
|
310
|
-
this.#dockerCompose = dockerCompose || null;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
get name(): string {
|
|
314
|
-
return this.#name;
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
get serviceDef(): DockerComposeServiceDef {
|
|
318
|
-
return this.#svcDef;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
get image(): ?string {
|
|
322
|
-
return this.#svcDef.image || null;
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
get defaultContainerName(): string {
|
|
326
|
-
return this.#svcDef.container_name || this.#name;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
get cmd(): string[] {
|
|
330
|
-
return this.#svcDef.command || [];
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
get envArgs(): string[] {
|
|
334
|
-
return parseEnv(this.#svcDef.environment);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Find (available) container name and alias(es)
|
|
339
|
-
* @param {boolean} avoidConflicts if `true`, find a container name that is unused
|
|
340
|
-
* @param {number} max maximum number of names to try
|
|
341
|
-
*/
|
|
342
|
-
async getNames(
|
|
343
|
-
avoidConflicts?: boolean = false,
|
|
344
|
-
max?: number = 100,
|
|
345
|
-
): Promise<ServiceNameInfo> {
|
|
346
|
-
/* eslint-disable no-await-in-loop */
|
|
347
|
-
for (let i = 0; i < max; i += 1) {
|
|
348
|
-
const suffix = i ? `-${i}` : '';
|
|
349
|
-
const testName = `${this.defaultContainerName}${suffix}`;
|
|
350
|
-
const container = await dockerContainerFind(testName, { all: true });
|
|
351
|
-
if (!avoidConflicts || !container) {
|
|
352
|
-
return {
|
|
353
|
-
name: testName,
|
|
354
|
-
aliases: [`${this.name}${suffix}`],
|
|
355
|
-
suffix,
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
/* eslint-enable no-await-in-loop */
|
|
360
|
-
throw new Error(
|
|
361
|
-
`Failed to find available container name for ${this.defaultContainerName}`,
|
|
362
|
-
);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
// Get (available) port mappings
|
|
366
|
-
async getPorts(
|
|
367
|
-
avoidConflicts?: boolean = false,
|
|
368
|
-
mapLocal?: boolean = true,
|
|
369
|
-
): Promise<ParsedPortInfo> {
|
|
370
|
-
return parsePorts(this.#svcDef.ports, avoidConflicts, mapLocal);
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
async getDefaultPortInfo(): Promise<ParsedPortInfo> {
|
|
374
|
-
if (!this.#parsedPorts) {
|
|
375
|
-
this.#parsedPorts = await this.getPorts();
|
|
376
|
-
}
|
|
377
|
-
return this.#parsedPorts;
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async getDefaultPorts(): Promise<PortMap[]> {
|
|
381
|
-
const { ports } = await this.getDefaultPortInfo();
|
|
382
|
-
return ports;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
async getDefaultPortArgs(): Promise<string[]> {
|
|
386
|
-
const { runArgs } = await this.getDefaultPortInfo();
|
|
387
|
-
return runArgs;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
async getDefaultUrls(): Promise<UrlMap[]> {
|
|
391
|
-
return this.constructor.getUrls(
|
|
392
|
-
await this.getDefaultPorts(),
|
|
393
|
-
this.defaultContainerName,
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
async getDefaultNetworkInfo(): Promise<ParsedNetworkInfo> {
|
|
398
|
-
if (!this.#parsedNetworks) {
|
|
399
|
-
this.#parsedNetworks = await parseNetworks(this.#svcDef.networks);
|
|
400
|
-
}
|
|
401
|
-
return this.#parsedNetworks;
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
async getDefaultNetworks(): Promise<string[]> {
|
|
405
|
-
const { networks } = await this.getDefaultNetworkInfo();
|
|
406
|
-
return networks;
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
async getDefaultNetworkArgs(): Promise<string[]> {
|
|
410
|
-
const { runArgs } = await this.getDefaultNetworkInfo();
|
|
411
|
-
return runArgs;
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
async getDefaultVolumeInfo(): Promise<ParsedVolumeInfo> {
|
|
415
|
-
if (!this.#parsedVolumes) {
|
|
416
|
-
this.#parsedVolumes = await parseVolumes(this.#svcDef.networks);
|
|
417
|
-
}
|
|
418
|
-
return this.#parsedVolumes;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
async getDefaultVolumes(): Promise<string[]> {
|
|
422
|
-
const { volumes } = await this.getDefaultVolumeInfo();
|
|
423
|
-
return volumes;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
async getDefaultVolumeArgs(): Promise<string[]> {
|
|
427
|
-
const { runArgs } = await this.getDefaultVolumeInfo();
|
|
428
|
-
return runArgs;
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
async pull() {
|
|
432
|
-
if (!this.image) {
|
|
433
|
-
throw new Error(`Cannot pull '${this.name}', no image configured.`);
|
|
434
|
-
}
|
|
435
|
-
await dockerPull({ image: this.image });
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
async getBaseRunArgs(): Promise<string[]> {
|
|
439
|
-
if (!this.#baseRunArgs) {
|
|
440
|
-
const envArgs = parseEnv(this.#svcDef.environment);
|
|
441
|
-
const ulArgs = parseULimits(this.#svcDef.ulimits);
|
|
442
|
-
const netArgs = await this.getDefaultNetworkArgs();
|
|
443
|
-
|
|
444
|
-
this.#baseRunArgs = ['--rm', ...envArgs, ...netArgs, ...ulArgs];
|
|
445
|
-
}
|
|
446
|
-
return this.#baseRunArgs;
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
async assembleRunArgs(
|
|
450
|
-
containerName?: string = this.defaultContainerName,
|
|
451
|
-
aliases?: string[] = [this.name],
|
|
452
|
-
additionalArgs?: string[],
|
|
453
|
-
): Promise<string[]> {
|
|
454
|
-
const additional = additionalArgs || [
|
|
455
|
-
...(await this.getDefaultPortArgs()),
|
|
456
|
-
...(await this.getDefaultVolumeArgs()),
|
|
457
|
-
];
|
|
458
|
-
return [
|
|
459
|
-
...(await this.getBaseRunArgs()),
|
|
460
|
-
...(containerName ? ['--name', containerName] : []),
|
|
461
|
-
...aliases.flatMap((a) => (a ? ['--network-alias', a] : [])),
|
|
462
|
-
...additional,
|
|
463
|
-
];
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
async getRunArgs(
|
|
467
|
-
avoidConflicts?: boolean = false,
|
|
468
|
-
mapLocalPorts?: boolean = true,
|
|
469
|
-
): Promise<string[]> {
|
|
470
|
-
const { name: cName, aliases, suffix } = await this.getNames(
|
|
471
|
-
avoidConflicts,
|
|
472
|
-
);
|
|
473
|
-
const { runArgs: pArgs } = await this.getPorts(
|
|
474
|
-
avoidConflicts,
|
|
475
|
-
mapLocalPorts,
|
|
476
|
-
);
|
|
477
|
-
const { runArgs: vArgs } = await parseVolumes(this.#svcDef.volumes, suffix);
|
|
478
|
-
return this.assembleRunArgs(cName, aliases, [...pArgs, ...vArgs]);
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
async up({
|
|
482
|
-
healthCheck,
|
|
483
|
-
avoidConflicts = false,
|
|
484
|
-
mapVolumes = true,
|
|
485
|
-
mapPorts = true,
|
|
486
|
-
cmd = this.cmd,
|
|
487
|
-
tracker = defaultTracker,
|
|
488
|
-
}: UpOptions = {}): Promise<UpResult> {
|
|
489
|
-
const { image } = this;
|
|
490
|
-
if (!image) {
|
|
491
|
-
throw new Error(
|
|
492
|
-
`Cannot bring up service '${this.name}', no image defined.`,
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
if (this.#tracker.containers.size) {
|
|
496
|
-
buildLog(
|
|
497
|
-
`Warning: up called on service '${this.name}' with already running container`,
|
|
498
|
-
);
|
|
499
|
-
}
|
|
500
|
-
const { name: containerName, aliases, suffix } = await this.getNames(
|
|
501
|
-
avoidConflicts,
|
|
502
|
-
);
|
|
503
|
-
const { runArgs: pArgs, ports } = await this.getPorts(
|
|
504
|
-
avoidConflicts,
|
|
505
|
-
mapPorts,
|
|
506
|
-
);
|
|
507
|
-
const { runArgs: vArgs, volumes } = mapVolumes
|
|
508
|
-
? await parseVolumes(this.#svcDef.volumes, suffix)
|
|
509
|
-
: { runArgs: [], volumes: [] };
|
|
510
|
-
|
|
511
|
-
let container = await dockerContainerFind(containerName, { all: true });
|
|
512
|
-
if (container && !(await container.isRunning())) {
|
|
513
|
-
await container.start();
|
|
514
|
-
}
|
|
515
|
-
if (!container) {
|
|
516
|
-
await this.pull();
|
|
517
|
-
await dockerComposeCreateNetworks(
|
|
518
|
-
await this.getDefaultNetworks(),
|
|
519
|
-
this.#dockerCompose,
|
|
520
|
-
this.#tracker,
|
|
521
|
-
);
|
|
522
|
-
await dockerComposeCreateVolumes(
|
|
523
|
-
volumes,
|
|
524
|
-
this.#dockerCompose,
|
|
525
|
-
this.#tracker,
|
|
526
|
-
);
|
|
527
|
-
const runArgs = await this.assembleRunArgs(containerName, aliases, [
|
|
528
|
-
...pArgs,
|
|
529
|
-
...vArgs,
|
|
530
|
-
]);
|
|
531
|
-
container = await dockerContainerRunDaemon({
|
|
532
|
-
image,
|
|
533
|
-
runArgs,
|
|
534
|
-
cmd,
|
|
535
|
-
});
|
|
536
|
-
} else {
|
|
537
|
-
buildLog(`Reusing existing container for '${this.name}' service.`);
|
|
538
|
-
}
|
|
539
|
-
// This service tracks the things it created
|
|
540
|
-
this.#tracker.containers.set(containerName, container);
|
|
541
|
-
// The passed tracker needs to track this service
|
|
542
|
-
tracker.services.set(this.name, this);
|
|
543
|
-
|
|
544
|
-
const idAlias = container.id.slice(0, 12);
|
|
545
|
-
aliases.push(idAlias);
|
|
546
|
-
const urls = this.constructor.getUrls(ports, idAlias);
|
|
547
|
-
|
|
548
|
-
const info: UpResult = {
|
|
549
|
-
service: this,
|
|
550
|
-
container,
|
|
551
|
-
containerName,
|
|
552
|
-
aliases,
|
|
553
|
-
ports,
|
|
554
|
-
volumes,
|
|
555
|
-
urls,
|
|
556
|
-
};
|
|
557
|
-
await healthCheck?.(info);
|
|
558
|
-
return info;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
async down({
|
|
562
|
-
includeDefaults = false,
|
|
563
|
-
includeVolumes = false,
|
|
564
|
-
includeNetworks = false,
|
|
565
|
-
}: {
|
|
566
|
-
includeDefaults?: boolean,
|
|
567
|
-
includeVolumes?: boolean,
|
|
568
|
-
includeNetworks?: boolean,
|
|
569
|
-
} = {}) {
|
|
570
|
-
buildLog(`Bringing down <${this.name}> service...`);
|
|
571
|
-
await dockerComposeTeardown({
|
|
572
|
-
tracker: this.#tracker,
|
|
573
|
-
includeVolumes,
|
|
574
|
-
includeNetworks,
|
|
575
|
-
});
|
|
576
|
-
if (includeDefaults) {
|
|
577
|
-
const container = await dockerContainerFind(this.defaultContainerName);
|
|
578
|
-
if (container) {
|
|
579
|
-
await container.teardown(true);
|
|
580
|
-
}
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
static async parse(
|
|
585
|
-
name: string,
|
|
586
|
-
force?: boolean = true,
|
|
587
|
-
dockerCompose?: ?(DockerCompose | string),
|
|
588
|
-
): Promise<?DockerComposeService> {
|
|
589
|
-
const svcDef = await getServiceDef(name, force, dockerCompose);
|
|
590
|
-
return svcDef ? new this(name, svcDef, dockerCompose) : null;
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
static getUrls(ports: PortMap[], alias: string): UrlMap[] {
|
|
594
|
-
return ports.map(({ local, docker }) => ({
|
|
595
|
-
local: local ? `http://localhost:${local}` : null,
|
|
596
|
-
docker: docker ? `http://${alias}:${docker}` : null,
|
|
597
|
-
}));
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
export async function dockerComposeGetAllServices(
|
|
602
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
603
|
-
): Promise<MapObj<string, DockerComposeService>> {
|
|
604
|
-
const { services } = await dockerComposeResolve(dockerCompose);
|
|
605
|
-
return mapValuesAsync(services, (s, name) =>
|
|
606
|
-
DockerComposeService.parse(name),
|
|
607
|
-
);
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
export async function dockerComposeTeardown({
|
|
611
|
-
includeDefaults = false,
|
|
612
|
-
includeVolumes = false,
|
|
613
|
-
includeNetworks = false,
|
|
614
|
-
dockerCompose,
|
|
615
|
-
tracker = defaultTracker,
|
|
616
|
-
}: {
|
|
617
|
-
includeDefaults?: boolean,
|
|
618
|
-
includeVolumes?: boolean,
|
|
619
|
-
includeNetworks?: boolean,
|
|
620
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
621
|
-
tracker?: DockerComposeResourceTracker,
|
|
622
|
-
} = {}): Promise<void> {
|
|
623
|
-
if (!tracker.cleaning) {
|
|
624
|
-
// eslint-disable-next-line no-param-reassign
|
|
625
|
-
tracker.cleaning = (async () => {
|
|
626
|
-
if (tracker.services.size) {
|
|
627
|
-
buildLog('Bringing down started docker services...');
|
|
628
|
-
const promises = Promise.all(
|
|
629
|
-
Array.from(tracker.services.values()).map(async (s) =>
|
|
630
|
-
s.down({ includeVolumes, includeNetworks }),
|
|
631
|
-
),
|
|
632
|
-
);
|
|
633
|
-
tracker.services.clear();
|
|
634
|
-
await promises;
|
|
635
|
-
}
|
|
636
|
-
if (includeDefaults) {
|
|
637
|
-
const { services } = await dockerComposeResolve(dockerCompose);
|
|
638
|
-
const svcNames = keys(services);
|
|
639
|
-
if (svcNames.length) {
|
|
640
|
-
buildLog('Bringing down default docker services...');
|
|
641
|
-
await Promise.all(
|
|
642
|
-
svcNames.map(async (s) =>
|
|
643
|
-
(await DockerComposeService.parse(s))?.down({
|
|
644
|
-
includeDefaults,
|
|
645
|
-
includeVolumes,
|
|
646
|
-
includeNetworks,
|
|
647
|
-
}),
|
|
648
|
-
),
|
|
649
|
-
);
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (tracker.containers.size) {
|
|
654
|
-
buildLog('Stopping created docker containers...');
|
|
655
|
-
const promises = Promise.all(
|
|
656
|
-
Array.from(tracker.containers.values()).map(async (c) =>
|
|
657
|
-
c.teardown(true),
|
|
658
|
-
),
|
|
659
|
-
);
|
|
660
|
-
tracker.containers.clear();
|
|
661
|
-
await promises;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
if (includeVolumes) {
|
|
665
|
-
if (tracker.volumes.size) {
|
|
666
|
-
buildLog('Removing created docker volumes...');
|
|
667
|
-
const promises = Promise.all(
|
|
668
|
-
Array.from(tracker.volumes.values()).map(async (v) => v.rm()),
|
|
669
|
-
);
|
|
670
|
-
tracker.volumes.clear();
|
|
671
|
-
await promises;
|
|
672
|
-
}
|
|
673
|
-
if (includeDefaults) {
|
|
674
|
-
buildLog('Removing default docker volumes...');
|
|
675
|
-
const { volumes } = await dockerComposeResolve(dockerCompose);
|
|
676
|
-
await Promise.all(
|
|
677
|
-
entries(volumes).map(async ([key, val]) => {
|
|
678
|
-
const name = val?.name || prefixName(key);
|
|
679
|
-
await dockerVolumeRm(name, true);
|
|
680
|
-
}),
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
if (includeNetworks) {
|
|
686
|
-
if (tracker.networks.size) {
|
|
687
|
-
buildLog('Removing created docker networks...');
|
|
688
|
-
const promises = Promise.all(
|
|
689
|
-
Array.from(tracker.networks.values()).map(async (n) => n.rm()),
|
|
690
|
-
);
|
|
691
|
-
tracker.networks.clear();
|
|
692
|
-
await promises;
|
|
693
|
-
}
|
|
694
|
-
if (includeDefaults) {
|
|
695
|
-
buildLog('Removing default docker networks...');
|
|
696
|
-
const { networks } = await dockerComposeResolve(dockerCompose);
|
|
697
|
-
await Promise.all(
|
|
698
|
-
entries(networks).map(async ([key, val]) => {
|
|
699
|
-
const name = val?.name || prefixName(key);
|
|
700
|
-
try {
|
|
701
|
-
await dockerNetworkDelete(name);
|
|
702
|
-
} catch (err) {
|
|
703
|
-
buildLog(`Error deleting network '${name}': ${err.message}`);
|
|
704
|
-
}
|
|
705
|
-
}),
|
|
706
|
-
);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
// eslint-disable-next-line no-param-reassign
|
|
710
|
-
tracker.cleaning = null;
|
|
711
|
-
})();
|
|
712
|
-
}
|
|
713
|
-
return tracker.cleaning;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
export type DockerContainerInfo = {|
|
|
717
|
-
...UpResult,
|
|
718
|
-
id: string,
|
|
719
|
-
image: string,
|
|
720
|
-
name?: ?string,
|
|
721
|
-
|
|
722
|
-
// for convenience, the first port mapping info
|
|
723
|
-
port?: ?number,
|
|
724
|
-
dockerPort?: ?number,
|
|
725
|
-
url?: ?string,
|
|
726
|
-
dockerUrl?: ?string,
|
|
727
|
-
|};
|
|
728
|
-
|
|
729
|
-
export async function dockerComposeRunService(
|
|
730
|
-
key: string,
|
|
731
|
-
upOptions?: UpOptions = {},
|
|
732
|
-
dockerCompose?: ?(string | DockerCompose),
|
|
733
|
-
): Promise<DockerContainerInfo> {
|
|
734
|
-
const service: ?DockerComposeService = await DockerComposeService.parse(
|
|
735
|
-
key,
|
|
736
|
-
false,
|
|
737
|
-
dockerCompose,
|
|
738
|
-
);
|
|
739
|
-
if (!service) {
|
|
740
|
-
throw new Error(`Failed to find service '${key}'`);
|
|
741
|
-
}
|
|
742
|
-
buildLog(`Starting <${service.name}> service...`);
|
|
743
|
-
const upResult: UpResult = await service.up(upOptions);
|
|
744
|
-
const {
|
|
745
|
-
container,
|
|
746
|
-
urls,
|
|
747
|
-
urls: [{ local: url, docker: dockerUrl }],
|
|
748
|
-
ports: [{ local: port, docker: dockerPort }],
|
|
749
|
-
} = upResult;
|
|
750
|
-
const { id, name, image } = container;
|
|
751
|
-
urls.forEach(
|
|
752
|
-
({ local }) =>
|
|
753
|
-
local && buildLog(`<${service.name}> accessible at ${local}`),
|
|
754
|
-
);
|
|
755
|
-
return {
|
|
756
|
-
...upResult,
|
|
757
|
-
id,
|
|
758
|
-
image,
|
|
759
|
-
name,
|
|
760
|
-
port,
|
|
761
|
-
dockerPort,
|
|
762
|
-
url,
|
|
763
|
-
dockerUrl,
|
|
764
|
-
};
|
|
765
|
-
}
|