@kapeta/local-cluster-service 0.7.4 → 0.7.6
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/definitions.d.ts +5 -1
- package/dist/cjs/index.js +8 -6
- package/dist/cjs/src/containerManager.js +8 -2
- package/dist/cjs/src/repositoryManager.js +52 -52
- package/dist/cjs/src/utils/BlockInstanceRunner.js +11 -5
- package/dist/cjs/src/utils/utils.d.ts +4 -0
- package/dist/cjs/src/utils/utils.js +19 -1
- package/dist/esm/index.js +8 -6
- package/dist/esm/src/containerManager.js +8 -2
- package/dist/esm/src/repositoryManager.js +52 -52
- package/dist/esm/src/utils/BlockInstanceRunner.js +12 -6
- package/dist/esm/src/utils/utils.d.ts +4 -0
- package/dist/esm/src/utils/utils.js +14 -0
- package/index.ts +9 -6
- package/package.json +2 -1
- package/src/containerManager.ts +9 -2
- package/src/repositoryManager.ts +58 -58
- package/src/utils/BlockInstanceRunner.ts +16 -6
- package/src/utils/utils.ts +18 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.7.6](https://github.com/kapetacom/local-cluster-service/compare/v0.7.5...v0.7.6) (2023-07-17)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Adjustments to make docker interaction work on Linux ([#45](https://github.com/kapetacom/local-cluster-service/issues/45)) ([4c9530c](https://github.com/kapetacom/local-cluster-service/commit/4c9530c1a509c490e95cc16029202650f79e127e))
|
7
|
+
|
8
|
+
## [0.7.5](https://github.com/kapetacom/local-cluster-service/compare/v0.7.4...v0.7.5) (2023-07-17)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Handle homedir on windows ([913fdd4](https://github.com/kapetacom/local-cluster-service/commit/913fdd4f853e4f79848c06afe2aaed72792e9ec5))
|
14
|
+
|
1
15
|
## [0.7.4](https://github.com/kapetacom/local-cluster-service/compare/v0.7.3...v0.7.4) (2023-07-17)
|
2
16
|
|
3
17
|
|
package/definitions.d.ts
CHANGED
@@ -5,6 +5,10 @@ declare module '@kapeta/nodejs-api-client' {
|
|
5
5
|
}
|
6
6
|
}
|
7
7
|
|
8
|
+
declare module 'recursive-watch' {
|
9
|
+
export default function watch(path:string, callback:(filename:string) => void):() => void;
|
10
|
+
}
|
11
|
+
|
8
12
|
declare module '@kapeta/nodejs-registry-utils' {
|
9
13
|
import { Dependency, Kind } from '@kapeta/schemas';
|
10
14
|
|
@@ -16,7 +20,7 @@ declare module '@kapeta/nodejs-registry-utils' {
|
|
16
20
|
export class RegistryService {
|
17
21
|
constructor(url: string);
|
18
22
|
|
19
|
-
|
23
|
+
getVersion(fullName: string, version: string): Promise<AssetVersion>;
|
20
24
|
}
|
21
25
|
|
22
26
|
export const Config: any;
|
package/dist/cjs/index.js
CHANGED
@@ -19,6 +19,7 @@ const routes_5 = __importDefault(require("./src/identities/routes"));
|
|
19
19
|
const routes_6 = __importDefault(require("./src/filesystem/routes"));
|
20
20
|
const routes_7 = __importDefault(require("./src/assets/routes"));
|
21
21
|
const routes_8 = __importDefault(require("./src/providers/routes"));
|
22
|
+
const utils_1 = require("./src/utils/utils");
|
22
23
|
let currentServer = null;
|
23
24
|
function createServer() {
|
24
25
|
const app = (0, express_1.default)();
|
@@ -30,11 +31,11 @@ function createServer() {
|
|
30
31
|
app.use('/files', routes_6.default);
|
31
32
|
app.use('/assets', routes_7.default);
|
32
33
|
app.use('/providers', routes_8.default);
|
33
|
-
app.use('/', (
|
34
|
-
console.error('
|
35
|
-
res.status(
|
34
|
+
app.use('/', (req, res) => {
|
35
|
+
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
36
|
+
res.status(400).send({
|
36
37
|
ok: false,
|
37
|
-
error:
|
38
|
+
error: 'Unknown'
|
38
39
|
});
|
39
40
|
});
|
40
41
|
const server = http_1.default.createServer(app);
|
@@ -90,7 +91,7 @@ exports.default = {
|
|
90
91
|
if (clusterHost !== host) {
|
91
92
|
storageService_1.storageService.put('cluster', 'host', host);
|
92
93
|
}
|
93
|
-
return new Promise((resolve, reject) => {
|
94
|
+
return new Promise(async (resolve, reject) => {
|
94
95
|
if (!currentServer) {
|
95
96
|
reject(new Error(`Current server wasn't set`));
|
96
97
|
return;
|
@@ -102,7 +103,8 @@ exports.default = {
|
|
102
103
|
}
|
103
104
|
reject(err);
|
104
105
|
});
|
105
|
-
|
106
|
+
const bindHost = (0, utils_1.getBindHost)(host);
|
107
|
+
currentServer.listen(port, bindHost, () => resolve({ host, port, dockerStatus: containerManager_1.containerManager.isAlive() }));
|
106
108
|
currentServer.host = host;
|
107
109
|
currentServer.port = port;
|
108
110
|
});
|
@@ -12,6 +12,7 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
12
|
const node_docker_api_1 = require("node-docker-api");
|
13
13
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
14
14
|
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
15
|
+
const utils_1 = require("./utils/utils");
|
15
16
|
const LABEL_PORT_PREFIX = 'kapeta_port-';
|
16
17
|
const NANO_SECOND = 1000000;
|
17
18
|
const HEALTH_CHECK_INTERVAL = 2000;
|
@@ -61,7 +62,11 @@ class ContainerManager {
|
|
61
62
|
await client.ping();
|
62
63
|
this._docker = client;
|
63
64
|
const versionInfo = await client.version();
|
64
|
-
this._version = versionInfo.Server?.Version;
|
65
|
+
this._version = versionInfo.Server?.Version ?? versionInfo.Version;
|
66
|
+
if (!this._version) {
|
67
|
+
console.warn('Failed to determine version from response', versionInfo);
|
68
|
+
this._version = '0.0.0';
|
69
|
+
}
|
65
70
|
this._alive = true;
|
66
71
|
console.log('Connected to docker daemon with version: %s', this._version);
|
67
72
|
return;
|
@@ -171,13 +176,14 @@ class ContainerManager {
|
|
171
176
|
kapeta: 'true',
|
172
177
|
};
|
173
178
|
await this.pull(image);
|
179
|
+
const bindHost = (0, utils_1.getBindHost)();
|
174
180
|
const ExposedPorts = {};
|
175
181
|
lodash_1.default.forEach(opts.ports, (portInfo, containerPort) => {
|
176
182
|
ExposedPorts['' + containerPort] = {};
|
177
183
|
PortBindings['' + containerPort] = [
|
178
184
|
{
|
179
185
|
HostPort: '' + portInfo.hostPort,
|
180
|
-
HostIp:
|
186
|
+
HostIp: bindHost,
|
181
187
|
},
|
182
188
|
];
|
183
189
|
Labels[LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
@@ -7,6 +7,7 @@ exports.repositoryManager = void 0;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
8
8
|
const node_os_1 = __importDefault(require("node:os"));
|
9
9
|
const node_path_1 = __importDefault(require("node:path"));
|
10
|
+
const recursive_watch_1 = __importDefault(require("recursive-watch"));
|
10
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
11
12
|
const local_cluster_config_1 = __importDefault(require("@kapeta/local-cluster-config"));
|
12
13
|
const nodejs_utils_1 = require("@kapeta/nodejs-utils");
|
@@ -39,70 +40,69 @@ class RepositoryManager {
|
|
39
40
|
let allDefinitions = local_cluster_config_1.default.getDefinitions();
|
40
41
|
console.log('Watching local repository for provider changes: %s', baseDir);
|
41
42
|
try {
|
42
|
-
this.watcher =
|
43
|
-
|
44
|
-
|
45
|
-
// Fallback to run without watch mode due to potential platform issues.
|
46
|
-
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
47
|
-
console.log('Unable to watch for changes. Changes to assets will not update automatically.');
|
48
|
-
return;
|
49
|
-
}
|
50
|
-
this.watcher.on('change', (eventType, filename) => {
|
51
|
-
if (!filename) {
|
52
|
-
return;
|
53
|
-
}
|
54
|
-
const [handle, name, version] = filename.toString().split(/\//g);
|
55
|
-
if (!name || !version) {
|
56
|
-
return;
|
57
|
-
}
|
58
|
-
if (!this.changeEventsEnabled) {
|
59
|
-
return;
|
60
|
-
}
|
61
|
-
const ymlPath = node_path_1.default.join(baseDir, handle, name, version, 'kapeta.yml');
|
62
|
-
const newDefinitions = local_cluster_config_1.default.getDefinitions();
|
63
|
-
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
64
|
-
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
65
|
-
const ymlExists = node_fs_1.default.existsSync(ymlPath);
|
66
|
-
let type;
|
67
|
-
if (ymlExists) {
|
68
|
-
if (currentDefinition) {
|
69
|
-
type = 'updated';
|
43
|
+
this.watcher = (0, recursive_watch_1.default)(baseDir, (filename) => {
|
44
|
+
if (!filename) {
|
45
|
+
return;
|
70
46
|
}
|
71
|
-
|
72
|
-
|
73
|
-
|
47
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
48
|
+
if (!name || !version) {
|
49
|
+
return;
|
74
50
|
}
|
75
|
-
|
76
|
-
//Other definition was added / updated - ignore
|
51
|
+
if (!this.changeEventsEnabled) {
|
77
52
|
return;
|
78
53
|
}
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
54
|
+
const ymlPath = node_path_1.default.join(baseDir, handle, name, version, 'kapeta.yml');
|
55
|
+
const newDefinitions = local_cluster_config_1.default.getDefinitions();
|
56
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
57
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
58
|
+
const ymlExists = node_fs_1.default.existsSync(ymlPath);
|
59
|
+
let type;
|
60
|
+
if (ymlExists) {
|
61
|
+
if (currentDefinition) {
|
62
|
+
type = 'updated';
|
63
|
+
}
|
64
|
+
else if (newDefinition) {
|
65
|
+
type = 'added';
|
66
|
+
currentDefinition = newDefinition;
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
//Other definition was added / updated - ignore
|
70
|
+
return;
|
71
|
+
}
|
86
72
|
}
|
87
73
|
else {
|
88
|
-
|
89
|
-
|
74
|
+
if (currentDefinition) {
|
75
|
+
const ref = (0, nodejs_utils_1.parseKapetaUri)(`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`).id;
|
76
|
+
delete INSTALL_ATTEMPTED[ref];
|
77
|
+
//Something was removed
|
78
|
+
type = 'removed';
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
//Other definition was removed - ignore
|
82
|
+
return;
|
83
|
+
}
|
90
84
|
}
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
}
|
85
|
+
const payload = {
|
86
|
+
type,
|
87
|
+
definition: currentDefinition?.definition,
|
88
|
+
asset: { handle, name, version },
|
89
|
+
};
|
90
|
+
allDefinitions = newDefinitions;
|
91
|
+
socketManager_1.socketManager.emit(`assets`, 'changed', payload);
|
92
|
+
});
|
93
|
+
}
|
94
|
+
catch (e) {
|
95
|
+
// Fallback to run without watch mode due to potential platform issues.
|
96
|
+
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
97
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.', e);
|
98
|
+
return;
|
99
|
+
}
|
100
100
|
}
|
101
101
|
stopListening() {
|
102
102
|
if (!this.watcher) {
|
103
103
|
return;
|
104
104
|
}
|
105
|
-
this.watcher
|
105
|
+
this.watcher();
|
106
106
|
this.watcher = undefined;
|
107
107
|
}
|
108
108
|
async _install(refs) {
|
@@ -160,6 +160,7 @@ class BlockInstanceRunner {
|
|
160
160
|
const dockerOpts = localContainer.options ?? {};
|
161
161
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
162
162
|
const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
|
163
|
+
const bindHost = (0, utils_1.getBindHost)();
|
163
164
|
const ExposedPorts = {};
|
164
165
|
const addonEnv = {};
|
165
166
|
const PortBindings = {};
|
@@ -173,7 +174,7 @@ class BlockInstanceRunner {
|
|
173
174
|
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
|
174
175
|
PortBindings[dockerPort] = [
|
175
176
|
{
|
176
|
-
HostIp:
|
177
|
+
HostIp: bindHost,
|
177
178
|
HostPort: `${publicPort}`,
|
178
179
|
},
|
179
180
|
];
|
@@ -204,7 +205,7 @@ class BlockInstanceRunner {
|
|
204
205
|
HostConfig: {
|
205
206
|
Binds: [
|
206
207
|
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${homeDir}/.kapeta`,
|
207
|
-
`${(0, containerManager_1.toLocalBindVolume)(baseDir)}:${workingDir}`,
|
208
|
+
`${(0, containerManager_1.toLocalBindVolume)(baseDir)}:${workingDir}`,
|
208
209
|
],
|
209
210
|
PortBindings,
|
210
211
|
},
|
@@ -290,6 +291,8 @@ class BlockInstanceRunner {
|
|
290
291
|
const containerName = `kapeta-block-instance-${blockInstance.id}`;
|
291
292
|
const logs = new LogData_1.LogData();
|
292
293
|
let container = await containerManager_1.containerManager.getContainerByName(containerName);
|
294
|
+
// For windows we need to default to root
|
295
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
293
296
|
if (container) {
|
294
297
|
const containerData = container.data;
|
295
298
|
if (containerData.State === 'running') {
|
@@ -315,7 +318,7 @@ class BlockInstanceRunner {
|
|
315
318
|
],
|
316
319
|
HostConfig: {
|
317
320
|
Binds: [
|
318
|
-
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${
|
321
|
+
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
319
322
|
],
|
320
323
|
},
|
321
324
|
});
|
@@ -388,6 +391,7 @@ class BlockInstanceRunner {
|
|
388
391
|
}
|
389
392
|
}
|
390
393
|
}
|
394
|
+
const bindHost = (0, utils_1.getBindHost)();
|
391
395
|
if (!container) {
|
392
396
|
const ExposedPorts = {};
|
393
397
|
const addonEnv = {};
|
@@ -401,7 +405,7 @@ class BlockInstanceRunner {
|
|
401
405
|
const publicPort = await serviceManager_1.serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
402
406
|
PortBindings[dockerPort] = [
|
403
407
|
{
|
404
|
-
HostIp:
|
408
|
+
HostIp: bindHost,
|
405
409
|
HostPort: `${publicPort}`,
|
406
410
|
},
|
407
411
|
];
|
@@ -419,6 +423,8 @@ class BlockInstanceRunner {
|
|
419
423
|
if (spec.local?.health) {
|
420
424
|
HealthCheck = containerManager_1.containerManager.toDockerHealth(spec.local?.health);
|
421
425
|
}
|
426
|
+
// For windows we need to default to root
|
427
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : local_cluster_config_1.default.getKapetaBasedir();
|
422
428
|
logs.addLog(`Creating new container for block: ${containerName}`);
|
423
429
|
container = await containerManager_1.containerManager.startContainer({
|
424
430
|
Image: dockerImage,
|
@@ -428,7 +434,7 @@ class BlockInstanceRunner {
|
|
428
434
|
HostConfig: {
|
429
435
|
Binds: [
|
430
436
|
`${(0, containerManager_1.toLocalBindVolume)(kapetaYmlPath)}:/kapeta.yml:ro`,
|
431
|
-
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${
|
437
|
+
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
432
438
|
],
|
433
439
|
PortBindings,
|
434
440
|
Mounts,
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
4
|
};
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
-
exports.readYML = void 0;
|
6
|
+
exports.getBindHost = exports.isLinux = exports.isMac = exports.isWindows = exports.readYML = void 0;
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
8
8
|
const yaml_1 = __importDefault(require("yaml"));
|
9
9
|
function readYML(path) {
|
@@ -16,3 +16,21 @@ function readYML(path) {
|
|
16
16
|
}
|
17
17
|
}
|
18
18
|
exports.readYML = readYML;
|
19
|
+
function isWindows() {
|
20
|
+
return 'win32' === process.platform;
|
21
|
+
}
|
22
|
+
exports.isWindows = isWindows;
|
23
|
+
function isMac() {
|
24
|
+
return 'darwin' === process.platform;
|
25
|
+
}
|
26
|
+
exports.isMac = isMac;
|
27
|
+
function isLinux() {
|
28
|
+
return !isWindows() && !isMac();
|
29
|
+
}
|
30
|
+
exports.isLinux = isLinux;
|
31
|
+
function getBindHost(preferredHost = '127.0.0.1') {
|
32
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
33
|
+
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
34
|
+
return isLinux() ? '0.0.0.0' : preferredHost;
|
35
|
+
}
|
36
|
+
exports.getBindHost = getBindHost;
|
package/dist/esm/index.js
CHANGED
@@ -14,6 +14,7 @@ import IdentitiesRoutes from './src/identities/routes';
|
|
14
14
|
import FilesystemRoutes from './src/filesystem/routes';
|
15
15
|
import AssetsRoutes from './src/assets/routes';
|
16
16
|
import ProviderRoutes from './src/providers/routes';
|
17
|
+
import { getBindHost } from './src/utils/utils';
|
17
18
|
let currentServer = null;
|
18
19
|
function createServer() {
|
19
20
|
const app = express();
|
@@ -25,11 +26,11 @@ function createServer() {
|
|
25
26
|
app.use('/files', FilesystemRoutes);
|
26
27
|
app.use('/assets', AssetsRoutes);
|
27
28
|
app.use('/providers', ProviderRoutes);
|
28
|
-
app.use('/', (
|
29
|
-
console.error('
|
30
|
-
res.status(
|
29
|
+
app.use('/', (req, res) => {
|
30
|
+
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
31
|
+
res.status(400).send({
|
31
32
|
ok: false,
|
32
|
-
error:
|
33
|
+
error: 'Unknown'
|
33
34
|
});
|
34
35
|
});
|
35
36
|
const server = HTTP.createServer(app);
|
@@ -85,7 +86,7 @@ export default {
|
|
85
86
|
if (clusterHost !== host) {
|
86
87
|
storageService.put('cluster', 'host', host);
|
87
88
|
}
|
88
|
-
return new Promise((resolve, reject) => {
|
89
|
+
return new Promise(async (resolve, reject) => {
|
89
90
|
if (!currentServer) {
|
90
91
|
reject(new Error(`Current server wasn't set`));
|
91
92
|
return;
|
@@ -97,7 +98,8 @@ export default {
|
|
97
98
|
}
|
98
99
|
reject(err);
|
99
100
|
});
|
100
|
-
|
101
|
+
const bindHost = getBindHost(host);
|
102
|
+
currentServer.listen(port, bindHost, () => resolve({ host, port, dockerStatus: containerManager.isAlive() }));
|
101
103
|
currentServer.host = host;
|
102
104
|
currentServer.port = port;
|
103
105
|
});
|
@@ -6,6 +6,7 @@ import FSExtra from 'fs-extra';
|
|
6
6
|
import { Docker } from 'node-docker-api';
|
7
7
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
8
8
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
9
|
+
import { getBindHost } from './utils/utils';
|
9
10
|
const LABEL_PORT_PREFIX = 'kapeta_port-';
|
10
11
|
const NANO_SECOND = 1000000;
|
11
12
|
const HEALTH_CHECK_INTERVAL = 2000;
|
@@ -55,7 +56,11 @@ class ContainerManager {
|
|
55
56
|
await client.ping();
|
56
57
|
this._docker = client;
|
57
58
|
const versionInfo = await client.version();
|
58
|
-
this._version = versionInfo.Server?.Version;
|
59
|
+
this._version = versionInfo.Server?.Version ?? versionInfo.Version;
|
60
|
+
if (!this._version) {
|
61
|
+
console.warn('Failed to determine version from response', versionInfo);
|
62
|
+
this._version = '0.0.0';
|
63
|
+
}
|
59
64
|
this._alive = true;
|
60
65
|
console.log('Connected to docker daemon with version: %s', this._version);
|
61
66
|
return;
|
@@ -165,13 +170,14 @@ class ContainerManager {
|
|
165
170
|
kapeta: 'true',
|
166
171
|
};
|
167
172
|
await this.pull(image);
|
173
|
+
const bindHost = getBindHost();
|
168
174
|
const ExposedPorts = {};
|
169
175
|
_.forEach(opts.ports, (portInfo, containerPort) => {
|
170
176
|
ExposedPorts['' + containerPort] = {};
|
171
177
|
PortBindings['' + containerPort] = [
|
172
178
|
{
|
173
179
|
HostPort: '' + portInfo.hostPort,
|
174
|
-
HostIp:
|
180
|
+
HostIp: bindHost,
|
175
181
|
},
|
176
182
|
];
|
177
183
|
Labels[LABEL_PORT_PREFIX + portInfo.hostPort] = portInfo.type;
|
@@ -1,6 +1,7 @@
|
|
1
1
|
import FS from 'node:fs';
|
2
2
|
import os from 'node:os';
|
3
3
|
import Path from 'node:path';
|
4
|
+
import watch from 'recursive-watch';
|
4
5
|
import FSExtra from 'fs-extra';
|
5
6
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
6
7
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
@@ -33,70 +34,69 @@ class RepositoryManager {
|
|
33
34
|
let allDefinitions = ClusterConfiguration.getDefinitions();
|
34
35
|
console.log('Watching local repository for provider changes: %s', baseDir);
|
35
36
|
try {
|
36
|
-
this.watcher =
|
37
|
-
|
38
|
-
|
39
|
-
// Fallback to run without watch mode due to potential platform issues.
|
40
|
-
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
41
|
-
console.log('Unable to watch for changes. Changes to assets will not update automatically.');
|
42
|
-
return;
|
43
|
-
}
|
44
|
-
this.watcher.on('change', (eventType, filename) => {
|
45
|
-
if (!filename) {
|
46
|
-
return;
|
47
|
-
}
|
48
|
-
const [handle, name, version] = filename.toString().split(/\//g);
|
49
|
-
if (!name || !version) {
|
50
|
-
return;
|
51
|
-
}
|
52
|
-
if (!this.changeEventsEnabled) {
|
53
|
-
return;
|
54
|
-
}
|
55
|
-
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
56
|
-
const newDefinitions = ClusterConfiguration.getDefinitions();
|
57
|
-
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
58
|
-
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
59
|
-
const ymlExists = FS.existsSync(ymlPath);
|
60
|
-
let type;
|
61
|
-
if (ymlExists) {
|
62
|
-
if (currentDefinition) {
|
63
|
-
type = 'updated';
|
37
|
+
this.watcher = watch(baseDir, (filename) => {
|
38
|
+
if (!filename) {
|
39
|
+
return;
|
64
40
|
}
|
65
|
-
|
66
|
-
|
67
|
-
|
41
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
42
|
+
if (!name || !version) {
|
43
|
+
return;
|
68
44
|
}
|
69
|
-
|
70
|
-
//Other definition was added / updated - ignore
|
45
|
+
if (!this.changeEventsEnabled) {
|
71
46
|
return;
|
72
47
|
}
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
48
|
+
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
49
|
+
const newDefinitions = ClusterConfiguration.getDefinitions();
|
50
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
51
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
52
|
+
const ymlExists = FS.existsSync(ymlPath);
|
53
|
+
let type;
|
54
|
+
if (ymlExists) {
|
55
|
+
if (currentDefinition) {
|
56
|
+
type = 'updated';
|
57
|
+
}
|
58
|
+
else if (newDefinition) {
|
59
|
+
type = 'added';
|
60
|
+
currentDefinition = newDefinition;
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
//Other definition was added / updated - ignore
|
64
|
+
return;
|
65
|
+
}
|
80
66
|
}
|
81
67
|
else {
|
82
|
-
|
83
|
-
|
68
|
+
if (currentDefinition) {
|
69
|
+
const ref = parseKapetaUri(`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`).id;
|
70
|
+
delete INSTALL_ATTEMPTED[ref];
|
71
|
+
//Something was removed
|
72
|
+
type = 'removed';
|
73
|
+
}
|
74
|
+
else {
|
75
|
+
//Other definition was removed - ignore
|
76
|
+
return;
|
77
|
+
}
|
84
78
|
}
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
}
|
79
|
+
const payload = {
|
80
|
+
type,
|
81
|
+
definition: currentDefinition?.definition,
|
82
|
+
asset: { handle, name, version },
|
83
|
+
};
|
84
|
+
allDefinitions = newDefinitions;
|
85
|
+
socketManager.emit(`assets`, 'changed', payload);
|
86
|
+
});
|
87
|
+
}
|
88
|
+
catch (e) {
|
89
|
+
// Fallback to run without watch mode due to potential platform issues.
|
90
|
+
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
91
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.', e);
|
92
|
+
return;
|
93
|
+
}
|
94
94
|
}
|
95
95
|
stopListening() {
|
96
96
|
if (!this.watcher) {
|
97
97
|
return;
|
98
98
|
}
|
99
|
-
this.watcher
|
99
|
+
this.watcher();
|
100
100
|
this.watcher = undefined;
|
101
101
|
}
|
102
102
|
async _install(refs) {
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import FS from 'node:fs';
|
2
2
|
import ClusterConfig from '@kapeta/local-cluster-config';
|
3
|
-
import { readYML } from './utils';
|
3
|
+
import { getBindHost, readYML } from './utils';
|
4
4
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
5
5
|
import { serviceManager } from '../serviceManager';
|
6
6
|
import { containerManager, toLocalBindVolume } from '../containerManager';
|
@@ -154,6 +154,7 @@ export class BlockInstanceRunner {
|
|
154
154
|
const dockerOpts = localContainer.options ?? {};
|
155
155
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
156
156
|
const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
|
157
|
+
const bindHost = getBindHost();
|
157
158
|
const ExposedPorts = {};
|
158
159
|
const addonEnv = {};
|
159
160
|
const PortBindings = {};
|
@@ -167,7 +168,7 @@ export class BlockInstanceRunner {
|
|
167
168
|
addonEnv[`KAPETA_LOCAL_SERVER_PORT_${portType.toUpperCase()}`] = '' + thisPort;
|
168
169
|
PortBindings[dockerPort] = [
|
169
170
|
{
|
170
|
-
HostIp:
|
171
|
+
HostIp: bindHost,
|
171
172
|
HostPort: `${publicPort}`,
|
172
173
|
},
|
173
174
|
];
|
@@ -198,7 +199,7 @@ export class BlockInstanceRunner {
|
|
198
199
|
HostConfig: {
|
199
200
|
Binds: [
|
200
201
|
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${homeDir}/.kapeta`,
|
201
|
-
`${toLocalBindVolume(baseDir)}:${workingDir}`,
|
202
|
+
`${toLocalBindVolume(baseDir)}:${workingDir}`,
|
202
203
|
],
|
203
204
|
PortBindings,
|
204
205
|
},
|
@@ -284,6 +285,8 @@ export class BlockInstanceRunner {
|
|
284
285
|
const containerName = `kapeta-block-instance-${blockInstance.id}`;
|
285
286
|
const logs = new LogData();
|
286
287
|
let container = await containerManager.getContainerByName(containerName);
|
288
|
+
// For windows we need to default to root
|
289
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
287
290
|
if (container) {
|
288
291
|
const containerData = container.data;
|
289
292
|
if (containerData.State === 'running') {
|
@@ -309,7 +312,7 @@ export class BlockInstanceRunner {
|
|
309
312
|
],
|
310
313
|
HostConfig: {
|
311
314
|
Binds: [
|
312
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${
|
315
|
+
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
313
316
|
],
|
314
317
|
},
|
315
318
|
});
|
@@ -382,6 +385,7 @@ export class BlockInstanceRunner {
|
|
382
385
|
}
|
383
386
|
}
|
384
387
|
}
|
388
|
+
const bindHost = getBindHost();
|
385
389
|
if (!container) {
|
386
390
|
const ExposedPorts = {};
|
387
391
|
const addonEnv = {};
|
@@ -395,7 +399,7 @@ export class BlockInstanceRunner {
|
|
395
399
|
const publicPort = await serviceManager.ensureServicePort(this._systemId, blockInstance.id, portType);
|
396
400
|
PortBindings[dockerPort] = [
|
397
401
|
{
|
398
|
-
HostIp:
|
402
|
+
HostIp: bindHost,
|
399
403
|
HostPort: `${publicPort}`,
|
400
404
|
},
|
401
405
|
];
|
@@ -413,6 +417,8 @@ export class BlockInstanceRunner {
|
|
413
417
|
if (spec.local?.health) {
|
414
418
|
HealthCheck = containerManager.toDockerHealth(spec.local?.health);
|
415
419
|
}
|
420
|
+
// For windows we need to default to root
|
421
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
416
422
|
logs.addLog(`Creating new container for block: ${containerName}`);
|
417
423
|
container = await containerManager.startContainer({
|
418
424
|
Image: dockerImage,
|
@@ -422,7 +428,7 @@ export class BlockInstanceRunner {
|
|
422
428
|
HostConfig: {
|
423
429
|
Binds: [
|
424
430
|
`${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
|
425
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${
|
431
|
+
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
426
432
|
],
|
427
433
|
PortBindings,
|
428
434
|
Mounts,
|
@@ -9,3 +9,17 @@ export function readYML(path) {
|
|
9
9
|
throw new Error('Failed to parse plan YAML: ' + err);
|
10
10
|
}
|
11
11
|
}
|
12
|
+
export function isWindows() {
|
13
|
+
return 'win32' === process.platform;
|
14
|
+
}
|
15
|
+
export function isMac() {
|
16
|
+
return 'darwin' === process.platform;
|
17
|
+
}
|
18
|
+
export function isLinux() {
|
19
|
+
return !isWindows() && !isMac();
|
20
|
+
}
|
21
|
+
export function getBindHost(preferredHost = '127.0.0.1') {
|
22
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
23
|
+
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
24
|
+
return isLinux() ? '0.0.0.0' : preferredHost;
|
25
|
+
}
|
package/index.ts
CHANGED
@@ -15,6 +15,7 @@ import IdentitiesRoutes from './src/identities/routes';
|
|
15
15
|
import FilesystemRoutes from './src/filesystem/routes';
|
16
16
|
import AssetsRoutes from './src/assets/routes';
|
17
17
|
import ProviderRoutes from './src/providers/routes';
|
18
|
+
import { getBindHost } from './src/utils/utils';
|
18
19
|
|
19
20
|
export type LocalClusterService = HTTP.Server & { host?: string; port?: number };
|
20
21
|
|
@@ -32,11 +33,11 @@ function createServer() {
|
|
32
33
|
app.use('/files', FilesystemRoutes);
|
33
34
|
app.use('/assets', AssetsRoutes);
|
34
35
|
app.use('/providers', ProviderRoutes);
|
35
|
-
app.use('/', (
|
36
|
-
console.error('
|
37
|
-
res.status(
|
36
|
+
app.use('/', (req: express.Request, res: express.Response) => {
|
37
|
+
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
38
|
+
res.status(400).send({
|
38
39
|
ok: false,
|
39
|
-
error:
|
40
|
+
error: 'Unknown'
|
40
41
|
});
|
41
42
|
});
|
42
43
|
const server = HTTP.createServer(app);
|
@@ -108,7 +109,7 @@ export default {
|
|
108
109
|
storageService.put('cluster', 'host', host);
|
109
110
|
}
|
110
111
|
|
111
|
-
return new Promise((resolve, reject) => {
|
112
|
+
return new Promise(async (resolve, reject) => {
|
112
113
|
if (!currentServer) {
|
113
114
|
reject(new Error(`Current server wasn't set`));
|
114
115
|
return;
|
@@ -121,7 +122,9 @@ export default {
|
|
121
122
|
reject(err);
|
122
123
|
});
|
123
124
|
|
124
|
-
|
125
|
+
const bindHost = getBindHost(host);
|
126
|
+
|
127
|
+
currentServer.listen(port, bindHost, () => resolve({ host, port, dockerStatus: containerManager.isAlive() }));
|
125
128
|
currentServer.host = host;
|
126
129
|
currentServer.port = port;
|
127
130
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.7.
|
3
|
+
"version": "0.7.6",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -59,6 +59,7 @@
|
|
59
59
|
"node-cache": "^5.1.2",
|
60
60
|
"node-docker-api": "1.1.22",
|
61
61
|
"node-uuid": "^1.4.8",
|
62
|
+
"recursive-watch": "^1.1.4",
|
62
63
|
"request": "2.88.2",
|
63
64
|
"request-promise": "4.2.6",
|
64
65
|
"socket.io": "^4.5.2",
|
package/src/containerManager.ts
CHANGED
@@ -7,6 +7,7 @@ import { Docker } from 'node-docker-api';
|
|
7
7
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
8
8
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
9
9
|
import { Container } from 'node-docker-api/lib/container';
|
10
|
+
import { getBindHost } from './utils/utils';
|
10
11
|
|
11
12
|
type StringMap = { [key: string]: string };
|
12
13
|
|
@@ -88,7 +89,11 @@ class ContainerManager {
|
|
88
89
|
await client.ping();
|
89
90
|
this._docker = client;
|
90
91
|
const versionInfo: any = await client.version();
|
91
|
-
this._version = versionInfo.Server?.Version;
|
92
|
+
this._version = versionInfo.Server?.Version ?? versionInfo.Version;
|
93
|
+
if (!this._version) {
|
94
|
+
console.warn('Failed to determine version from response', versionInfo);
|
95
|
+
this._version = '0.0.0';
|
96
|
+
}
|
92
97
|
this._alive = true;
|
93
98
|
console.log('Connected to docker daemon with version: %s', this._version);
|
94
99
|
return;
|
@@ -226,6 +231,8 @@ class ContainerManager {
|
|
226
231
|
|
227
232
|
await this.pull(image);
|
228
233
|
|
234
|
+
const bindHost = getBindHost();
|
235
|
+
|
229
236
|
const ExposedPorts: { [key: string]: any } = {};
|
230
237
|
|
231
238
|
_.forEach(opts.ports, (portInfo: any, containerPort) => {
|
@@ -233,7 +240,7 @@ class ContainerManager {
|
|
233
240
|
PortBindings['' + containerPort] = [
|
234
241
|
{
|
235
242
|
HostPort: '' + portInfo.hostPort,
|
236
|
-
HostIp:
|
243
|
+
HostIp: bindHost,
|
237
244
|
},
|
238
245
|
];
|
239
246
|
|
package/src/repositoryManager.ts
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import FS from 'node:fs';
|
2
2
|
import os from 'node:os';
|
3
3
|
import Path from 'node:path';
|
4
|
+
import watch from 'recursive-watch';
|
4
5
|
import FSExtra, { FSWatcher } from 'fs-extra';
|
5
6
|
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
6
7
|
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
@@ -15,7 +16,7 @@ class RepositoryManager {
|
|
15
16
|
private changeEventsEnabled: boolean;
|
16
17
|
private _registryService: RegistryService;
|
17
18
|
private _cache: { [key: string]: boolean };
|
18
|
-
private watcher?:
|
19
|
+
private watcher?: () => void;
|
19
20
|
private _installQueue: (() => Promise<void>)[];
|
20
21
|
private _processing: boolean = false;
|
21
22
|
constructor() {
|
@@ -40,74 +41,73 @@ class RepositoryManager {
|
|
40
41
|
|
41
42
|
console.log('Watching local repository for provider changes: %s', baseDir);
|
42
43
|
try {
|
43
|
-
this.watcher =
|
44
|
+
this.watcher = watch(baseDir, (filename:string) => {
|
45
|
+
if (!filename) {
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
|
49
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
50
|
+
if (!name || !version) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
54
|
+
if (!this.changeEventsEnabled) {
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
59
|
+
const newDefinitions = ClusterConfiguration.getDefinitions();
|
60
|
+
|
61
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
62
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
63
|
+
const ymlExists = FS.existsSync(ymlPath);
|
64
|
+
let type;
|
65
|
+
if (ymlExists) {
|
66
|
+
if (currentDefinition) {
|
67
|
+
type = 'updated';
|
68
|
+
} else if (newDefinition) {
|
69
|
+
type = 'added';
|
70
|
+
currentDefinition = newDefinition;
|
71
|
+
} else {
|
72
|
+
//Other definition was added / updated - ignore
|
73
|
+
return;
|
74
|
+
}
|
75
|
+
} else {
|
76
|
+
if (currentDefinition) {
|
77
|
+
const ref = parseKapetaUri(
|
78
|
+
`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`
|
79
|
+
).id;
|
80
|
+
delete INSTALL_ATTEMPTED[ref];
|
81
|
+
//Something was removed
|
82
|
+
type = 'removed';
|
83
|
+
} else {
|
84
|
+
//Other definition was removed - ignore
|
85
|
+
return;
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
const payload = {
|
90
|
+
type,
|
91
|
+
definition: currentDefinition?.definition,
|
92
|
+
asset: { handle, name, version },
|
93
|
+
};
|
94
|
+
|
95
|
+
allDefinitions = newDefinitions;
|
96
|
+
socketManager.emit(`assets`, 'changed', payload);
|
97
|
+
});
|
44
98
|
} catch (e) {
|
45
99
|
// Fallback to run without watch mode due to potential platform issues.
|
46
100
|
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
47
|
-
console.log('Unable to watch for changes. Changes to assets will not update automatically.');
|
101
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.', e);
|
48
102
|
return;
|
49
103
|
}
|
50
|
-
this.watcher.on('change', (eventType, filename) => {
|
51
|
-
if (!filename) {
|
52
|
-
return;
|
53
|
-
}
|
54
|
-
|
55
|
-
const [handle, name, version] = filename.toString().split(/\//g);
|
56
|
-
if (!name || !version) {
|
57
|
-
return;
|
58
|
-
}
|
59
|
-
|
60
|
-
if (!this.changeEventsEnabled) {
|
61
|
-
return;
|
62
|
-
}
|
63
|
-
|
64
|
-
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
65
|
-
const newDefinitions = ClusterConfiguration.getDefinitions();
|
66
|
-
|
67
|
-
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
68
|
-
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
69
|
-
const ymlExists = FS.existsSync(ymlPath);
|
70
|
-
let type;
|
71
|
-
if (ymlExists) {
|
72
|
-
if (currentDefinition) {
|
73
|
-
type = 'updated';
|
74
|
-
} else if (newDefinition) {
|
75
|
-
type = 'added';
|
76
|
-
currentDefinition = newDefinition;
|
77
|
-
} else {
|
78
|
-
//Other definition was added / updated - ignore
|
79
|
-
return;
|
80
|
-
}
|
81
|
-
} else {
|
82
|
-
if (currentDefinition) {
|
83
|
-
const ref = parseKapetaUri(
|
84
|
-
`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`
|
85
|
-
).id;
|
86
|
-
delete INSTALL_ATTEMPTED[ref];
|
87
|
-
//Something was removed
|
88
|
-
type = 'removed';
|
89
|
-
} else {
|
90
|
-
//Other definition was removed - ignore
|
91
|
-
return;
|
92
|
-
}
|
93
|
-
}
|
94
|
-
|
95
|
-
const payload = {
|
96
|
-
type,
|
97
|
-
definition: currentDefinition?.definition,
|
98
|
-
asset: { handle, name, version },
|
99
|
-
};
|
100
|
-
|
101
|
-
allDefinitions = newDefinitions;
|
102
|
-
socketManager.emit(`assets`, 'changed', payload);
|
103
|
-
});
|
104
104
|
}
|
105
105
|
|
106
106
|
stopListening() {
|
107
107
|
if (!this.watcher) {
|
108
108
|
return;
|
109
109
|
}
|
110
|
-
this.watcher
|
110
|
+
this.watcher();
|
111
111
|
this.watcher = undefined;
|
112
112
|
}
|
113
113
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import FS from 'node:fs';
|
2
2
|
import ClusterConfig, { DefinitionInfo } from '@kapeta/local-cluster-config';
|
3
|
-
import { readYML } from './utils';
|
3
|
+
import { getBindHost, readYML } from './utils';
|
4
4
|
import { KapetaURI, parseKapetaUri } from '@kapeta/nodejs-utils';
|
5
5
|
import { serviceManager } from '../serviceManager';
|
6
6
|
import { containerManager, DockerMounts, toLocalBindVolume } from '../containerManager';
|
@@ -199,6 +199,8 @@ export class BlockInstanceRunner {
|
|
199
199
|
const homeDir = localContainer.userHome ? localContainer.userHome : '/root';
|
200
200
|
const workingDir = localContainer.workingDir ? localContainer.workingDir : '/workspace';
|
201
201
|
|
202
|
+
const bindHost = getBindHost();
|
203
|
+
|
202
204
|
const ExposedPorts: AnyMap = {};
|
203
205
|
const addonEnv: StringMap = {};
|
204
206
|
const PortBindings: AnyMap = {};
|
@@ -214,7 +216,7 @@ export class BlockInstanceRunner {
|
|
214
216
|
|
215
217
|
PortBindings[dockerPort] = [
|
216
218
|
{
|
217
|
-
HostIp:
|
219
|
+
HostIp: bindHost,
|
218
220
|
HostPort: `${publicPort}`,
|
219
221
|
},
|
220
222
|
];
|
@@ -248,7 +250,7 @@ export class BlockInstanceRunner {
|
|
248
250
|
HostConfig: {
|
249
251
|
Binds: [
|
250
252
|
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${homeDir}/.kapeta`,
|
251
|
-
`${toLocalBindVolume(baseDir)}:${workingDir}`,
|
253
|
+
`${toLocalBindVolume(baseDir)}:${workingDir}`,
|
252
254
|
],
|
253
255
|
PortBindings,
|
254
256
|
},
|
@@ -352,6 +354,9 @@ export class BlockInstanceRunner {
|
|
352
354
|
const logs = new LogData();
|
353
355
|
let container = await containerManager.getContainerByName(containerName);
|
354
356
|
|
357
|
+
// For windows we need to default to root
|
358
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
359
|
+
|
355
360
|
if (container) {
|
356
361
|
const containerData = container.data as any;
|
357
362
|
if (containerData.State === 'running') {
|
@@ -376,7 +381,7 @@ export class BlockInstanceRunner {
|
|
376
381
|
],
|
377
382
|
HostConfig: {
|
378
383
|
Binds: [
|
379
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${
|
384
|
+
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
380
385
|
],
|
381
386
|
},
|
382
387
|
});
|
@@ -461,6 +466,8 @@ export class BlockInstanceRunner {
|
|
461
466
|
}
|
462
467
|
}
|
463
468
|
|
469
|
+
const bindHost = getBindHost();
|
470
|
+
|
464
471
|
if (!container) {
|
465
472
|
const ExposedPorts: AnyMap = {};
|
466
473
|
const addonEnv: StringMap = {};
|
@@ -479,7 +486,7 @@ export class BlockInstanceRunner {
|
|
479
486
|
);
|
480
487
|
PortBindings[dockerPort] = [
|
481
488
|
{
|
482
|
-
HostIp:
|
489
|
+
HostIp: bindHost,
|
483
490
|
HostPort: `${publicPort}`,
|
484
491
|
},
|
485
492
|
];
|
@@ -503,6 +510,9 @@ export class BlockInstanceRunner {
|
|
503
510
|
HealthCheck = containerManager.toDockerHealth(spec.local?.health);
|
504
511
|
}
|
505
512
|
|
513
|
+
// For windows we need to default to root
|
514
|
+
const innerHome = process.platform === 'win32' ? '/root/.kapeta' : ClusterConfig.getKapetaBasedir();
|
515
|
+
|
506
516
|
logs.addLog(`Creating new container for block: ${containerName}`);
|
507
517
|
container = await containerManager.startContainer({
|
508
518
|
Image: dockerImage,
|
@@ -512,7 +522,7 @@ export class BlockInstanceRunner {
|
|
512
522
|
HostConfig: {
|
513
523
|
Binds: [
|
514
524
|
`${toLocalBindVolume(kapetaYmlPath)}:/kapeta.yml:ro`,
|
515
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${
|
525
|
+
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
516
526
|
],
|
517
527
|
PortBindings,
|
518
528
|
Mounts,
|
package/src/utils/utils.ts
CHANGED
@@ -10,3 +10,21 @@ export function readYML(path: string) {
|
|
10
10
|
throw new Error('Failed to parse plan YAML: ' + err);
|
11
11
|
}
|
12
12
|
}
|
13
|
+
|
14
|
+
export function isWindows() {
|
15
|
+
return 'win32' === process.platform;
|
16
|
+
}
|
17
|
+
|
18
|
+
export function isMac() {
|
19
|
+
return 'darwin' === process.platform;
|
20
|
+
}
|
21
|
+
|
22
|
+
export function isLinux() {
|
23
|
+
return !isWindows() && !isMac();
|
24
|
+
}
|
25
|
+
|
26
|
+
export function getBindHost(preferredHost = '127.0.0.1') {
|
27
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
28
|
+
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
29
|
+
return isLinux() ? '0.0.0.0' : preferredHost;
|
30
|
+
}
|