@kapeta/local-cluster-service 0.9.1 → 0.10.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/CHANGELOG.md +14 -0
- package/dist/cjs/src/containerManager.d.ts +4 -8
- package/dist/cjs/src/containerManager.js +69 -64
- package/dist/cjs/src/instanceManager.js +4 -2
- package/dist/cjs/src/operatorManager.js +40 -25
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +3 -1
- package/dist/cjs/src/utils/BlockInstanceRunner.js +159 -242
- package/dist/esm/src/containerManager.d.ts +4 -8
- package/dist/esm/src/containerManager.js +69 -64
- package/dist/esm/src/instanceManager.js +4 -2
- package/dist/esm/src/operatorManager.js +42 -27
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +3 -1
- package/dist/esm/src/utils/BlockInstanceRunner.js +159 -242
- package/package.json +1 -1
- package/src/containerManager.ts +69 -73
- package/src/instanceManager.ts +8 -2
- package/src/operatorManager.ts +52 -26
- package/src/utils/BlockInstanceRunner.ts +203 -272
@@ -3,10 +3,11 @@ import md5 from 'md5';
|
|
3
3
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
4
4
|
import { serviceManager } from './serviceManager';
|
5
5
|
import { storageService } from './storageService';
|
6
|
-
import { containerManager } from './containerManager';
|
6
|
+
import { CONTAINER_LABEL_PORT_PREFIX, ContainerInfo, containerManager } from './containerManager';
|
7
7
|
import FSExtra from 'fs-extra';
|
8
8
|
import { definitionsManager } from './definitionsManager';
|
9
|
-
import { normalizeKapetaUri } from './utils/utils';
|
9
|
+
import { getBindHost, normalizeKapetaUri } from './utils/utils';
|
10
|
+
import _ from 'lodash';
|
10
11
|
const KIND_OPERATOR = 'core/resource-type-operator';
|
11
12
|
class Operator {
|
12
13
|
_data;
|
@@ -132,32 +133,46 @@ class OperatorManager {
|
|
132
133
|
}
|
133
134
|
const mounts = containerManager.createMounts(resourceType, operatorData.mounts);
|
134
135
|
const containerName = containerBaseName + '-' + md5(nameParts.join('_'));
|
135
|
-
|
136
|
-
const
|
137
|
-
|
138
|
-
|
139
|
-
}
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
136
|
+
const PortBindings = {};
|
137
|
+
const Env = [];
|
138
|
+
const Labels = {
|
139
|
+
kapeta: 'true',
|
140
|
+
};
|
141
|
+
const bindHost = getBindHost();
|
142
|
+
const ExposedPorts = {};
|
143
|
+
_.forEach(ports, (portInfo, containerPort) => {
|
144
|
+
ExposedPorts['' + containerPort] = {};
|
145
|
+
PortBindings['' + containerPort] = [
|
146
|
+
{
|
147
|
+
HostPort: '' + portInfo.hostPort,
|
148
|
+
HostIp: bindHost,
|
149
|
+
},
|
150
|
+
];
|
151
|
+
Labels[CONTAINER_LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
152
|
+
});
|
153
|
+
const Mounts = containerManager.toDockerMounts(mounts);
|
154
|
+
_.forEach(operatorData.env, (value, name) => {
|
155
|
+
Env.push(name + '=' + value);
|
156
|
+
});
|
157
|
+
let HealthCheck = undefined;
|
158
|
+
if (operatorData.health) {
|
159
|
+
HealthCheck = containerManager.toDockerHealth(operatorData.health);
|
159
160
|
}
|
160
|
-
|
161
|
+
const container = await containerManager.ensureContainer({
|
162
|
+
name: containerName,
|
163
|
+
Image: operatorData.image,
|
164
|
+
Hostname: containerName + '.kapeta',
|
165
|
+
Labels,
|
166
|
+
Cmd: operatorData.cmd,
|
167
|
+
ExposedPorts,
|
168
|
+
Env,
|
169
|
+
HealthCheck,
|
170
|
+
HostConfig: {
|
171
|
+
PortBindings,
|
172
|
+
Mounts,
|
173
|
+
},
|
174
|
+
});
|
175
|
+
return new ContainerInfo(container);
|
161
176
|
}
|
162
177
|
}
|
163
178
|
export const operatorManager = new OperatorManager();
|
@@ -14,7 +14,6 @@ export declare class BlockInstanceRunner {
|
|
14
14
|
* Starts local process
|
15
15
|
*/
|
16
16
|
private _startLocalProcess;
|
17
|
-
private _handleContainer;
|
18
17
|
private _startDockerProcess;
|
19
18
|
/**
|
20
19
|
*
|
@@ -26,4 +25,7 @@ export declare class BlockInstanceRunner {
|
|
26
25
|
* @private
|
27
26
|
*/
|
28
27
|
_startOperatorProcess(blockInstance: BlockProcessParams, blockUri: KapetaURI, providerDefinition: DefinitionInfo, env: StringMap): Promise<ProcessInfo>;
|
28
|
+
private getDockerPortBindings;
|
29
|
+
private ensureContainer;
|
30
|
+
private _handleContainer;
|
29
31
|
}
|
@@ -94,7 +94,7 @@ export class BlockInstanceRunner {
|
|
94
94
|
processInfo = await this._startLocalProcess(blockInstance, blockUri, env, assetVersion);
|
95
95
|
}
|
96
96
|
else {
|
97
|
-
processInfo = await this._startDockerProcess(blockInstance, blockUri, env);
|
97
|
+
processInfo = await this._startDockerProcess(blockInstance, blockUri, env, assetVersion);
|
98
98
|
}
|
99
99
|
if (portTypes.length > 0) {
|
100
100
|
processInfo.portType = portTypes[0];
|
@@ -128,57 +128,16 @@ export class BlockInstanceRunner {
|
|
128
128
|
throw new Error(`Missing docker image information: ${JSON.stringify(localContainer)}`);
|
129
129
|
}
|
130
130
|
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
131
|
-
const logs = new LogData();
|
132
|
-
logs.addLog(`Starting block ${blockInstance.ref}`);
|
133
|
-
let containerInfo = await containerManager.getContainerByName(containerName);
|
134
|
-
let container = containerInfo?.native;
|
135
|
-
console.log('Starting dev container', containerName);
|
136
|
-
if (containerInfo) {
|
137
|
-
console.log(`Dev container already exists. Deleting...`);
|
138
|
-
try {
|
139
|
-
await containerInfo.remove({
|
140
|
-
force: true,
|
141
|
-
});
|
142
|
-
}
|
143
|
-
catch (e) {
|
144
|
-
throw new Error('Failed to delete existing container: ' + e.message);
|
145
|
-
}
|
146
|
-
container = undefined;
|
147
|
-
containerInfo = undefined;
|
148
|
-
}
|
149
|
-
logs.addLog(`Creating new container for block: ${containerName}`);
|
150
|
-
console.log('Creating new dev container', containerName, dockerImage);
|
151
|
-
await containerManager.pull(dockerImage);
|
152
131
|
const startCmd = localContainer.handlers?.onCreate ? localContainer.handlers.onCreate : '';
|
153
132
|
const dockerOpts = localContainer.options ?? {};
|
154
133
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
155
134
|
const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
|
156
|
-
const
|
157
|
-
const ExposedPorts = {};
|
158
|
-
const addonEnv = {};
|
159
|
-
const PortBindings = {};
|
160
|
-
const portTypes = getProviderPorts(assetVersion);
|
161
|
-
let port = 80;
|
162
|
-
const promises = portTypes.map(async (portType) => {
|
163
|
-
const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
164
|
-
const thisPort = port++; //TODO: Not sure how we should handle multiple ports or non-HTTP ports
|
165
|
-
const dockerPort = `${thisPort}/tcp`;
|
166
|
-
ExposedPorts[dockerPort] = {};
|
167
|
-
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
|
168
|
-
PortBindings[dockerPort] = [
|
169
|
-
{
|
170
|
-
HostIp: bindHost,
|
171
|
-
HostPort: `${publicPort}`,
|
172
|
-
},
|
173
|
-
];
|
174
|
-
});
|
175
|
-
await Promise.all(promises);
|
135
|
+
const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
|
176
136
|
let HealthCheck = undefined;
|
177
137
|
if (localContainer.healthcheck) {
|
178
138
|
HealthCheck = containerManager.toDockerHealth({ cmd: localContainer.healthcheck });
|
179
139
|
}
|
180
|
-
|
181
|
-
container = await containerManager.startContainer({
|
140
|
+
return this.ensureContainer({
|
182
141
|
Image: dockerImage,
|
183
142
|
name: containerName,
|
184
143
|
WorkingDir: workingDir,
|
@@ -205,8 +164,163 @@ export class BlockInstanceRunner {
|
|
205
164
|
},
|
206
165
|
...dockerOpts,
|
207
166
|
});
|
167
|
+
}
|
168
|
+
async _startDockerProcess(blockInstance, blockInfo, env, assetVersion) {
|
169
|
+
const { versionFile } = ClusterConfig.getRepositoryAssetInfoPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
170
|
+
const versionYml = versionFile;
|
171
|
+
if (!FS.existsSync(versionYml)) {
|
172
|
+
throw new Error(`Did not find version info at the expected path: ${versionYml}`);
|
173
|
+
}
|
174
|
+
const versionInfo = readYML(versionYml);
|
175
|
+
if (versionInfo?.artifact?.type !== 'docker') {
|
176
|
+
throw new Error(`Unsupported artifact type: ${versionInfo?.artifact?.type}`);
|
177
|
+
}
|
178
|
+
const dockerImage = versionInfo?.artifact?.details?.primary;
|
179
|
+
if (!dockerImage) {
|
180
|
+
throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
|
181
|
+
}
|
182
|
+
const { PortBindings, ExposedPorts, addonEnv } = await this.getDockerPortBindings(blockInstance, assetVersion);
|
183
|
+
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
184
|
+
// For windows we need to default to root
|
185
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
186
|
+
return this.ensureContainer({
|
187
|
+
Image: dockerImage,
|
188
|
+
name: containerName,
|
189
|
+
ExposedPorts,
|
190
|
+
Labels: {
|
191
|
+
instance: blockInstance.id,
|
192
|
+
},
|
193
|
+
Env: [
|
194
|
+
...DOCKER_ENV_VARS,
|
195
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
196
|
+
...Object.entries({
|
197
|
+
...env,
|
198
|
+
...addonEnv
|
199
|
+
}).map(([key, value]) => `${key}=${value}`),
|
200
|
+
],
|
201
|
+
HostConfig: {
|
202
|
+
Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
|
203
|
+
PortBindings,
|
204
|
+
},
|
205
|
+
});
|
206
|
+
}
|
207
|
+
/**
|
208
|
+
*
|
209
|
+
* @param blockInstance
|
210
|
+
* @param blockUri
|
211
|
+
* @param providerDefinition
|
212
|
+
* @param {{[key:string]:string}} env
|
213
|
+
* @return {Promise<ProcessDetails>}
|
214
|
+
* @private
|
215
|
+
*/
|
216
|
+
async _startOperatorProcess(blockInstance, blockUri, providerDefinition, env) {
|
217
|
+
const { assetFile } = ClusterConfig.getRepositoryAssetInfoPath(blockUri.handle, blockUri.name, blockUri.version);
|
218
|
+
const kapetaYmlPath = assetFile;
|
219
|
+
if (!FS.existsSync(kapetaYmlPath)) {
|
220
|
+
throw new Error(`Did not find kapeta.yml at the expected path: ${kapetaYmlPath}`);
|
221
|
+
}
|
222
|
+
const spec = providerDefinition.definition.spec;
|
223
|
+
const providerRef = `${providerDefinition.definition.metadata.name}:${providerDefinition.version}`;
|
224
|
+
if (!spec?.local?.image) {
|
225
|
+
throw new Error(`Provider did not have local image: ${providerRef}`);
|
226
|
+
}
|
227
|
+
const dockerImage = spec?.local?.image;
|
228
|
+
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
229
|
+
const logs = new LogData();
|
230
|
+
const bindHost = getBindHost();
|
231
|
+
const ExposedPorts = {};
|
232
|
+
const addonEnv = {};
|
233
|
+
const PortBindings = {};
|
234
|
+
let HealthCheck = undefined;
|
235
|
+
let Mounts = [];
|
236
|
+
const promises = Object.entries(spec.local.ports).map(async ([portType, value]) => {
|
237
|
+
const dockerPort = `${value.port}/${value.type}`;
|
238
|
+
ExposedPorts[dockerPort] = {};
|
239
|
+
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
|
240
|
+
const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
241
|
+
PortBindings[dockerPort] = [
|
242
|
+
{
|
243
|
+
HostIp: bindHost,
|
244
|
+
HostPort: `${publicPort}`,
|
245
|
+
},
|
246
|
+
];
|
247
|
+
});
|
248
|
+
await Promise.all(promises);
|
249
|
+
if (spec.local?.env) {
|
250
|
+
Object.entries(spec.local.env).forEach(([key, value]) => {
|
251
|
+
addonEnv[key] = value;
|
252
|
+
});
|
253
|
+
}
|
254
|
+
if (spec.local?.mounts) {
|
255
|
+
const mounts = containerManager.createMounts(blockUri.id, spec.local.mounts);
|
256
|
+
Mounts = containerManager.toDockerMounts(mounts);
|
257
|
+
}
|
258
|
+
if (spec.local?.health) {
|
259
|
+
HealthCheck = containerManager.toDockerHealth(spec.local?.health);
|
260
|
+
}
|
261
|
+
// For windows we need to default to root
|
262
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
263
|
+
logs.addLog(`Creating new container for block: ${containerName}`);
|
264
|
+
const out = await this.ensureContainer({
|
265
|
+
Image: dockerImage,
|
266
|
+
name: containerName,
|
267
|
+
ExposedPorts,
|
268
|
+
HealthCheck,
|
269
|
+
HostConfig: {
|
270
|
+
Binds: [
|
271
|
+
`${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
|
272
|
+
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
273
|
+
],
|
274
|
+
PortBindings,
|
275
|
+
Mounts,
|
276
|
+
},
|
277
|
+
Labels: {
|
278
|
+
instance: blockInstance.id,
|
279
|
+
},
|
280
|
+
Env: [
|
281
|
+
`KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
|
282
|
+
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
283
|
+
...DOCKER_ENV_VARS,
|
284
|
+
...Object.entries({
|
285
|
+
...env,
|
286
|
+
...addonEnv,
|
287
|
+
}).map(([key, value]) => `${key}=${value}`),
|
288
|
+
],
|
289
|
+
});
|
290
|
+
const portTypes = spec.local.ports ? Object.keys(spec.local.ports) : [];
|
291
|
+
if (portTypes.length > 0) {
|
292
|
+
out.portType = portTypes[0];
|
293
|
+
}
|
294
|
+
return out;
|
295
|
+
}
|
296
|
+
async getDockerPortBindings(blockInstance, assetVersion) {
|
297
|
+
const bindHost = getBindHost();
|
298
|
+
const ExposedPorts = {};
|
299
|
+
const addonEnv = {};
|
300
|
+
const PortBindings = {};
|
301
|
+
const portTypes = getProviderPorts(assetVersion);
|
302
|
+
let port = 80;
|
303
|
+
const promises = portTypes.map(async (portType) => {
|
304
|
+
const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
305
|
+
const thisPort = port++; //TODO: Not sure how we should handle multiple ports or non-HTTP ports
|
306
|
+
const dockerPort = `${thisPort}/tcp`;
|
307
|
+
ExposedPorts[dockerPort] = {};
|
308
|
+
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
|
309
|
+
PortBindings[dockerPort] = [
|
310
|
+
{
|
311
|
+
HostIp: bindHost,
|
312
|
+
HostPort: `${publicPort}`,
|
313
|
+
},
|
314
|
+
];
|
315
|
+
});
|
316
|
+
await Promise.all(promises);
|
317
|
+
return { PortBindings, ExposedPorts, addonEnv };
|
318
|
+
}
|
319
|
+
async ensureContainer(opts) {
|
320
|
+
const logs = new LogData();
|
321
|
+
const container = await containerManager.ensureContainer(opts);
|
208
322
|
try {
|
209
|
-
if (HealthCheck) {
|
323
|
+
if (opts.HealthCheck) {
|
210
324
|
await containerManager.waitForHealthy(container);
|
211
325
|
}
|
212
326
|
else {
|
@@ -268,201 +382,4 @@ export class BlockInstanceRunner {
|
|
268
382
|
},
|
269
383
|
};
|
270
384
|
}
|
271
|
-
async _startDockerProcess(blockInstance, blockInfo, env) {
|
272
|
-
const { versionFile } = ClusterConfig.getRepositoryAssetInfoPath(blockInfo.handle, blockInfo.name, blockInfo.version);
|
273
|
-
const versionYml = versionFile;
|
274
|
-
if (!FS.existsSync(versionYml)) {
|
275
|
-
throw new Error(`Did not find version info at the expected path: ${versionYml}`);
|
276
|
-
}
|
277
|
-
const versionInfo = readYML(versionYml);
|
278
|
-
if (versionInfo?.artifact?.type !== 'docker') {
|
279
|
-
throw new Error(`Unsupported artifact type: ${versionInfo?.artifact?.type}`);
|
280
|
-
}
|
281
|
-
const dockerImage = versionInfo?.artifact?.details?.primary;
|
282
|
-
if (!dockerImage) {
|
283
|
-
throw new Error(`Missing docker image information: ${JSON.stringify(versionInfo?.artifact?.details)}`);
|
284
|
-
}
|
285
|
-
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
286
|
-
const logs = new LogData();
|
287
|
-
const containerInfo = await containerManager.getContainerByName(containerName);
|
288
|
-
let container = containerInfo?.native;
|
289
|
-
// For windows we need to default to root
|
290
|
-
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
291
|
-
if (container) {
|
292
|
-
const containerData = container.data;
|
293
|
-
if (containerData.State === 'running') {
|
294
|
-
logs.addLog(`Found existing running container for block: ${containerName}`);
|
295
|
-
}
|
296
|
-
else {
|
297
|
-
logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
|
298
|
-
await container.start();
|
299
|
-
}
|
300
|
-
}
|
301
|
-
else {
|
302
|
-
logs.addLog(`Creating new container for block: ${containerName}`);
|
303
|
-
container = await containerManager.startContainer({
|
304
|
-
Image: dockerImage,
|
305
|
-
name: containerName,
|
306
|
-
Labels: {
|
307
|
-
instance: blockInstance.id,
|
308
|
-
},
|
309
|
-
Env: [
|
310
|
-
...DOCKER_ENV_VARS,
|
311
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
312
|
-
...Object.entries(env).map(([key, value]) => `${key}=${value}`),
|
313
|
-
],
|
314
|
-
HostConfig: {
|
315
|
-
Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
|
316
|
-
},
|
317
|
-
});
|
318
|
-
try {
|
319
|
-
await containerManager.waitForReady(container);
|
320
|
-
}
|
321
|
-
catch (e) {
|
322
|
-
logs.addLog(e.message, 'ERROR');
|
323
|
-
}
|
324
|
-
}
|
325
|
-
return this._handleContainer(container, logs);
|
326
|
-
}
|
327
|
-
/**
|
328
|
-
*
|
329
|
-
* @param blockInstance
|
330
|
-
* @param blockUri
|
331
|
-
* @param providerDefinition
|
332
|
-
* @param {{[key:string]:string}} env
|
333
|
-
* @return {Promise<ProcessDetails>}
|
334
|
-
* @private
|
335
|
-
*/
|
336
|
-
async _startOperatorProcess(blockInstance, blockUri, providerDefinition, env) {
|
337
|
-
const { assetFile } = ClusterConfig.getRepositoryAssetInfoPath(blockUri.handle, blockUri.name, blockUri.version);
|
338
|
-
const kapetaYmlPath = assetFile;
|
339
|
-
if (!FS.existsSync(kapetaYmlPath)) {
|
340
|
-
throw new Error(`Did not find kapeta.yml at the expected path: ${kapetaYmlPath}`);
|
341
|
-
}
|
342
|
-
const spec = providerDefinition.definition.spec;
|
343
|
-
const providerRef = `${providerDefinition.definition.metadata.name}:${providerDefinition.version}`;
|
344
|
-
if (!spec?.local?.image) {
|
345
|
-
throw new Error(`Provider did not have local image: ${providerRef}`);
|
346
|
-
}
|
347
|
-
const dockerImage = spec?.local?.image;
|
348
|
-
try {
|
349
|
-
await containerManager.pull(dockerImage);
|
350
|
-
}
|
351
|
-
catch (e) {
|
352
|
-
console.warn('Failed to pull image. Continuing...', e);
|
353
|
-
}
|
354
|
-
const containerName = getBlockInstanceContainerName(blockInstance.id);
|
355
|
-
const logs = new LogData();
|
356
|
-
const containerInfo = await containerManager.getContainerByName(containerName);
|
357
|
-
let container = containerInfo?.native;
|
358
|
-
if (container) {
|
359
|
-
const containerData = container.data;
|
360
|
-
if (containerData.State === 'running') {
|
361
|
-
logs.addLog(`Found existing running container for block: ${containerName}`);
|
362
|
-
}
|
363
|
-
else {
|
364
|
-
if (containerData.State?.ExitCode > 0) {
|
365
|
-
logs.addLog(`Container exited with code: ${containerData.State.ExitCode}. Deleting...`);
|
366
|
-
try {
|
367
|
-
await containerManager.remove(container);
|
368
|
-
}
|
369
|
-
catch (e) { }
|
370
|
-
container = undefined;
|
371
|
-
}
|
372
|
-
else {
|
373
|
-
logs.addLog(`Found existing container for block: ${containerName}. Starting now`);
|
374
|
-
try {
|
375
|
-
await container.start();
|
376
|
-
}
|
377
|
-
catch (e) {
|
378
|
-
console.warn('Failed to start container. Deleting...', e);
|
379
|
-
try {
|
380
|
-
await containerManager.remove(container);
|
381
|
-
}
|
382
|
-
catch (e) { }
|
383
|
-
container = undefined;
|
384
|
-
}
|
385
|
-
}
|
386
|
-
}
|
387
|
-
}
|
388
|
-
const bindHost = getBindHost();
|
389
|
-
if (!container) {
|
390
|
-
const ExposedPorts = {};
|
391
|
-
const addonEnv = {};
|
392
|
-
const PortBindings = {};
|
393
|
-
let HealthCheck = undefined;
|
394
|
-
let Mounts = [];
|
395
|
-
const promises = Object.entries(spec.local.ports).map(async ([portType, value]) => {
|
396
|
-
const dockerPort = `${value.port}/${value.type}`;
|
397
|
-
ExposedPorts[dockerPort] = {};
|
398
|
-
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = value.port;
|
399
|
-
const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
400
|
-
PortBindings[dockerPort] = [
|
401
|
-
{
|
402
|
-
HostIp: bindHost,
|
403
|
-
HostPort: `${publicPort}`,
|
404
|
-
},
|
405
|
-
];
|
406
|
-
});
|
407
|
-
await Promise.all(promises);
|
408
|
-
if (spec.local?.env) {
|
409
|
-
Object.entries(spec.local.env).forEach(([key, value]) => {
|
410
|
-
addonEnv[key] = value;
|
411
|
-
});
|
412
|
-
}
|
413
|
-
if (spec.local?.mounts) {
|
414
|
-
const mounts = containerManager.createMounts(blockUri.id, spec.local.mounts);
|
415
|
-
Mounts = containerManager.toDockerMounts(mounts);
|
416
|
-
}
|
417
|
-
if (spec.local?.health) {
|
418
|
-
HealthCheck = containerManager.toDockerHealth(spec.local?.health);
|
419
|
-
}
|
420
|
-
// For windows we need to default to root
|
421
|
-
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
422
|
-
logs.addLog(`Creating new container for block: ${containerName}`);
|
423
|
-
container = await containerManager.startContainer({
|
424
|
-
Image: dockerImage,
|
425
|
-
name: containerName,
|
426
|
-
ExposedPorts,
|
427
|
-
HealthCheck,
|
428
|
-
HostConfig: {
|
429
|
-
Binds: [
|
430
|
-
`${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
|
431
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
432
|
-
],
|
433
|
-
PortBindings,
|
434
|
-
Mounts,
|
435
|
-
},
|
436
|
-
Labels: {
|
437
|
-
instance: blockInstance.id,
|
438
|
-
},
|
439
|
-
Env: [
|
440
|
-
`KAPETA_INSTANCE_NAME=${blockInstance.ref}`,
|
441
|
-
`KAPETA_LOCAL_CLUSTER_PORT=${clusterService.getClusterServicePort()}`,
|
442
|
-
...DOCKER_ENV_VARS,
|
443
|
-
...Object.entries({
|
444
|
-
...env,
|
445
|
-
...addonEnv,
|
446
|
-
}).map(([key, value]) => `${key}=${value}`),
|
447
|
-
],
|
448
|
-
});
|
449
|
-
try {
|
450
|
-
if (HealthCheck) {
|
451
|
-
await containerManager.waitForHealthy(container);
|
452
|
-
}
|
453
|
-
else {
|
454
|
-
await containerManager.waitForReady(container);
|
455
|
-
}
|
456
|
-
}
|
457
|
-
catch (e) {
|
458
|
-
logs.addLog(e.message, 'ERROR');
|
459
|
-
}
|
460
|
-
}
|
461
|
-
const out = await this._handleContainer(container, logs, true);
|
462
|
-
const portTypes = spec.local.ports ? Object.keys(spec.local.ports) : [];
|
463
|
-
if (portTypes.length > 0) {
|
464
|
-
out.portType = portTypes[0];
|
465
|
-
}
|
466
|
-
return out;
|
467
|
-
}
|
468
385
|
}
|