@kapeta/local-cluster-service 0.8.1 → 0.8.3
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 +1 -1
- package/dist/cjs/index.d.ts +3 -0
- package/dist/cjs/index.js +35 -1
- package/dist/cjs/src/attachments/routes.js +4 -4
- package/dist/cjs/src/containerManager.d.ts +1 -0
- package/dist/cjs/src/containerManager.js +19 -0
- package/dist/cjs/src/socketManager.d.ts +1 -0
- package/dist/cjs/src/socketManager.js +3 -3
- package/dist/cjs/src/utils/BlockInstanceRunner.js +1 -3
- package/dist/cjs/src/utils/utils.js +1 -1
- package/dist/cjs/start.js +1 -0
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +35 -1
- package/dist/esm/src/attachments/routes.js +5 -5
- package/dist/esm/src/containerManager.d.ts +1 -0
- package/dist/esm/src/containerManager.js +19 -0
- package/dist/esm/src/socketManager.d.ts +1 -0
- package/dist/esm/src/socketManager.js +3 -3
- package/dist/esm/src/utils/BlockInstanceRunner.js +1 -3
- package/dist/esm/src/utils/utils.js +1 -1
- package/dist/esm/start.js +1 -0
- package/index.ts +44 -2
- package/package.json +4 -4
- package/src/attachments/routes.ts +8 -8
- package/src/containerManager.ts +20 -0
- package/src/identities/routes.ts +2 -3
- package/src/repositoryManager.ts +7 -7
- package/src/socketManager.ts +4 -4
- package/src/storageService.ts +1 -1
- package/src/utils/BlockInstanceRunner.ts +2 -4
- package/src/utils/utils.ts +2 -2
- package/start.ts +1 -0
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
## [0.8.3](https://github.com/kapetacom/local-cluster-service/compare/v0.8.2...v0.8.3) (2023-07-23)
|
2
|
+
|
3
|
+
|
4
|
+
### Bug Fixes
|
5
|
+
|
6
|
+
* Format ([736158b](https://github.com/kapetacom/local-cluster-service/commit/736158b8685aa2ac1193cdabbbb34d81f6d2e302))
|
7
|
+
|
8
|
+
## [0.8.2](https://github.com/kapetacom/local-cluster-service/compare/v0.8.1...v0.8.2) (2023-07-23)
|
9
|
+
|
10
|
+
|
11
|
+
### Bug Fixes
|
12
|
+
|
13
|
+
* Check for existing cluster services on the same point and exit if it exists ([#47](https://github.com/kapetacom/local-cluster-service/issues/47)) ([3c76c3c](https://github.com/kapetacom/local-cluster-service/commit/3c76c3c24927212e4a06dc627e6c7262b2c60c4f))
|
14
|
+
|
1
15
|
## [0.8.1](https://github.com/kapetacom/local-cluster-service/compare/v0.8.0...v0.8.1) (2023-07-22)
|
2
16
|
|
3
17
|
|
package/definitions.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
declare module 'recursive-watch' {
|
2
|
-
export default function watch(path:string, callback:(filename:string) => void):() => void;
|
2
|
+
export default function watch(path: string, callback: (filename: string) => void): () => void;
|
3
3
|
}
|
4
4
|
|
5
5
|
declare module '@kapeta/nodejs-registry-utils' {
|
package/dist/cjs/index.d.ts
CHANGED
@@ -12,6 +12,9 @@ export type StartResult = {
|
|
12
12
|
declare const _default: {
|
13
13
|
isRunning: () => boolean;
|
14
14
|
getCurrentPort: () => number | undefined;
|
15
|
+
ping: (host: string, port: number) => Promise<{
|
16
|
+
ok: boolean;
|
17
|
+
}>;
|
15
18
|
/**
|
16
19
|
* Starts the local cluster service.
|
17
20
|
* resolves when listening is done with port number. Rejects if listening failed.
|
package/dist/cjs/index.js
CHANGED
@@ -21,6 +21,7 @@ const routes_7 = __importDefault(require("./src/assets/routes"));
|
|
21
21
|
const routes_8 = __importDefault(require("./src/providers/routes"));
|
22
22
|
const routes_9 = __importDefault(require("./src/attachments/routes"));
|
23
23
|
const utils_1 = require("./src/utils/utils");
|
24
|
+
const request_1 = __importDefault(require("request"));
|
24
25
|
let currentServer = null;
|
25
26
|
function createServer() {
|
26
27
|
const app = (0, express_1.default)();
|
@@ -33,11 +34,23 @@ function createServer() {
|
|
33
34
|
app.use('/assets', routes_7.default);
|
34
35
|
app.use('/providers', routes_8.default);
|
35
36
|
app.use('/attachments', routes_9.default);
|
37
|
+
app.get('/status', async (req, res) => {
|
38
|
+
res.send({
|
39
|
+
ok: true,
|
40
|
+
dockerStatus: await containerManager_1.containerManager.checkAlive(),
|
41
|
+
socketStatus: socketManager_1.socketManager.isAlive(),
|
42
|
+
});
|
43
|
+
});
|
44
|
+
app.get('/ping', async (req, res) => {
|
45
|
+
res.send({
|
46
|
+
ok: true,
|
47
|
+
});
|
48
|
+
});
|
36
49
|
app.use('/', (req, res) => {
|
37
50
|
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
38
51
|
res.status(400).send({
|
39
52
|
ok: false,
|
40
|
-
error: 'Unknown'
|
53
|
+
error: 'Unknown',
|
41
54
|
});
|
42
55
|
});
|
43
56
|
const server = http_1.default.createServer(app);
|
@@ -61,6 +74,17 @@ exports.default = {
|
|
61
74
|
}
|
62
75
|
return currentServer.port;
|
63
76
|
},
|
77
|
+
ping: async function (host, port) {
|
78
|
+
return new Promise((resolve, reject) => {
|
79
|
+
request_1.default.get(`http://${host}:${port}/ping`, (err, res, body) => {
|
80
|
+
if (err) {
|
81
|
+
reject(err);
|
82
|
+
return;
|
83
|
+
}
|
84
|
+
resolve(JSON.parse(body));
|
85
|
+
});
|
86
|
+
});
|
87
|
+
},
|
64
88
|
/**
|
65
89
|
* Starts the local cluster service.
|
66
90
|
* resolves when listening is done with port number. Rejects if listening failed.
|
@@ -83,6 +107,16 @@ exports.default = {
|
|
83
107
|
if (clusterHost) {
|
84
108
|
clusterService_1.clusterService.setClusterServiceHost(clusterHost);
|
85
109
|
}
|
110
|
+
let pingResult = undefined;
|
111
|
+
try {
|
112
|
+
pingResult = await this.ping(clusterHost, clusterPort);
|
113
|
+
}
|
114
|
+
catch (e) {
|
115
|
+
//Ignore - expected to not be running since we're starting it
|
116
|
+
}
|
117
|
+
if (pingResult?.ok) {
|
118
|
+
throw new Error(`Cluster service already running on: ${clusterHost}:${clusterPort}.`);
|
119
|
+
}
|
86
120
|
await clusterService_1.clusterService.init();
|
87
121
|
currentServer = createServer();
|
88
122
|
const port = clusterService_1.clusterService.getClusterServicePort();
|
@@ -20,21 +20,21 @@ router.put('/:handle/:name', async (req, res) => {
|
|
20
20
|
if (!req.headers['content-type']) {
|
21
21
|
res.status(400).send({
|
22
22
|
status: 400,
|
23
|
-
error: 'Missing content-type header'
|
23
|
+
error: 'Missing content-type header',
|
24
24
|
});
|
25
25
|
return;
|
26
26
|
}
|
27
27
|
if (!req.headers['content-length']) {
|
28
28
|
res.status(400).send({
|
29
29
|
status: 400,
|
30
|
-
error: 'Missing content-length header'
|
30
|
+
error: 'Missing content-length header',
|
31
31
|
});
|
32
32
|
return;
|
33
33
|
}
|
34
34
|
if (!req.headers['content-disposition']) {
|
35
35
|
res.status(400).send({
|
36
36
|
status: 400,
|
37
|
-
error: 'Missing content-disposition header'
|
37
|
+
error: 'Missing content-disposition header',
|
38
38
|
});
|
39
39
|
return;
|
40
40
|
}
|
@@ -50,7 +50,7 @@ router.put('/:handle/:name', async (req, res) => {
|
|
50
50
|
'content-length': req.headers['content-length'],
|
51
51
|
'content-disposition': req.headers['content-disposition'],
|
52
52
|
},
|
53
|
-
body: req
|
53
|
+
body: req,
|
54
54
|
});
|
55
55
|
res.send(result);
|
56
56
|
}
|
@@ -30,6 +30,7 @@ declare class ContainerManager {
|
|
30
30
|
private _version;
|
31
31
|
constructor();
|
32
32
|
initialize(): Promise<void>;
|
33
|
+
checkAlive(): Promise<boolean>;
|
33
34
|
isAlive(): boolean;
|
34
35
|
getMountPoint(kind: string, mountName: string): string;
|
35
36
|
createMounts(kind: string, mountOpts: StringMap): StringMap;
|
@@ -77,6 +77,25 @@ class ContainerManager {
|
|
77
77
|
}
|
78
78
|
throw new Error('Could not connect to docker daemon. Please make sure docker is running and working.');
|
79
79
|
}
|
80
|
+
async checkAlive() {
|
81
|
+
if (!this._docker) {
|
82
|
+
try {
|
83
|
+
await this.initialize();
|
84
|
+
}
|
85
|
+
catch (e) {
|
86
|
+
this._alive = false;
|
87
|
+
}
|
88
|
+
return this._alive;
|
89
|
+
}
|
90
|
+
try {
|
91
|
+
await this._docker.ping();
|
92
|
+
this._alive = true;
|
93
|
+
}
|
94
|
+
catch (e) {
|
95
|
+
this._alive = false;
|
96
|
+
}
|
97
|
+
return this._alive;
|
98
|
+
}
|
80
99
|
isAlive() {
|
81
100
|
return this._alive;
|
82
101
|
}
|
@@ -14,10 +14,12 @@ class SocketManager {
|
|
14
14
|
return this;
|
15
15
|
}
|
16
16
|
setIo(io) {
|
17
|
-
console.log('Socket server ready');
|
18
17
|
this._io = io;
|
19
18
|
this._bindIO();
|
20
19
|
}
|
20
|
+
isAlive() {
|
21
|
+
return !!this._io;
|
22
|
+
}
|
21
23
|
get io() {
|
22
24
|
if (!this._io) {
|
23
25
|
throw new Error('Socket server not ready');
|
@@ -37,11 +39,9 @@ class SocketManager {
|
|
37
39
|
_bindSocket(socket) {
|
38
40
|
socket.on('disconnect', () => this._handleSocketDestroyed(socket));
|
39
41
|
socket.on('join', (id) => {
|
40
|
-
console.log('socket joined ', id);
|
41
42
|
socket.join(id);
|
42
43
|
});
|
43
44
|
socket.on('leave', (id) => {
|
44
|
-
console.log('socket left ', id);
|
45
45
|
socket.leave(id);
|
46
46
|
});
|
47
47
|
}
|
@@ -317,9 +317,7 @@ class BlockInstanceRunner {
|
|
317
317
|
...Object.entries(env).map(([key, value]) => `${key}=${value}`),
|
318
318
|
],
|
319
319
|
HostConfig: {
|
320
|
-
Binds: [
|
321
|
-
`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`,
|
322
|
-
],
|
320
|
+
Binds: [`${(0, containerManager_1.toLocalBindVolume)(local_cluster_config_1.default.getKapetaBasedir())}:${innerHome}`],
|
323
321
|
},
|
324
322
|
});
|
325
323
|
try {
|
@@ -29,7 +29,7 @@ function isLinux() {
|
|
29
29
|
}
|
30
30
|
exports.isLinux = isLinux;
|
31
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.
|
32
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
33
33
|
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
34
34
|
return isLinux() ? '0.0.0.0' : preferredHost;
|
35
35
|
}
|
package/dist/cjs/start.js
CHANGED
package/dist/esm/index.d.ts
CHANGED
@@ -12,6 +12,9 @@ export type StartResult = {
|
|
12
12
|
declare const _default: {
|
13
13
|
isRunning: () => boolean;
|
14
14
|
getCurrentPort: () => number | undefined;
|
15
|
+
ping: (host: string, port: number) => Promise<{
|
16
|
+
ok: boolean;
|
17
|
+
}>;
|
15
18
|
/**
|
16
19
|
* Starts the local cluster service.
|
17
20
|
* resolves when listening is done with port number. Rejects if listening failed.
|
package/dist/esm/index.js
CHANGED
@@ -16,6 +16,7 @@ import AssetsRoutes from './src/assets/routes';
|
|
16
16
|
import ProviderRoutes from './src/providers/routes';
|
17
17
|
import AttachmentRoutes from './src/attachments/routes';
|
18
18
|
import { getBindHost } from './src/utils/utils';
|
19
|
+
import request from 'request';
|
19
20
|
let currentServer = null;
|
20
21
|
function createServer() {
|
21
22
|
const app = express();
|
@@ -28,11 +29,23 @@ function createServer() {
|
|
28
29
|
app.use('/assets', AssetsRoutes);
|
29
30
|
app.use('/providers', ProviderRoutes);
|
30
31
|
app.use('/attachments', AttachmentRoutes);
|
32
|
+
app.get('/status', async (req, res) => {
|
33
|
+
res.send({
|
34
|
+
ok: true,
|
35
|
+
dockerStatus: await containerManager.checkAlive(),
|
36
|
+
socketStatus: socketManager.isAlive(),
|
37
|
+
});
|
38
|
+
});
|
39
|
+
app.get('/ping', async (req, res) => {
|
40
|
+
res.send({
|
41
|
+
ok: true,
|
42
|
+
});
|
43
|
+
});
|
31
44
|
app.use('/', (req, res) => {
|
32
45
|
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
33
46
|
res.status(400).send({
|
34
47
|
ok: false,
|
35
|
-
error: 'Unknown'
|
48
|
+
error: 'Unknown',
|
36
49
|
});
|
37
50
|
});
|
38
51
|
const server = HTTP.createServer(app);
|
@@ -56,6 +69,17 @@ export default {
|
|
56
69
|
}
|
57
70
|
return currentServer.port;
|
58
71
|
},
|
72
|
+
ping: async function (host, port) {
|
73
|
+
return new Promise((resolve, reject) => {
|
74
|
+
request.get(`http://${host}:${port}/ping`, (err, res, body) => {
|
75
|
+
if (err) {
|
76
|
+
reject(err);
|
77
|
+
return;
|
78
|
+
}
|
79
|
+
resolve(JSON.parse(body));
|
80
|
+
});
|
81
|
+
});
|
82
|
+
},
|
59
83
|
/**
|
60
84
|
* Starts the local cluster service.
|
61
85
|
* resolves when listening is done with port number. Rejects if listening failed.
|
@@ -78,6 +102,16 @@ export default {
|
|
78
102
|
if (clusterHost) {
|
79
103
|
clusterService.setClusterServiceHost(clusterHost);
|
80
104
|
}
|
105
|
+
let pingResult = undefined;
|
106
|
+
try {
|
107
|
+
pingResult = await this.ping(clusterHost, clusterPort);
|
108
|
+
}
|
109
|
+
catch (e) {
|
110
|
+
//Ignore - expected to not be running since we're starting it
|
111
|
+
}
|
112
|
+
if (pingResult?.ok) {
|
113
|
+
throw new Error(`Cluster service already running on: ${clusterHost}:${clusterPort}.`);
|
114
|
+
}
|
81
115
|
await clusterService.init();
|
82
116
|
currentServer = createServer();
|
83
117
|
const port = clusterService.getClusterServicePort();
|
@@ -1,7 +1,7 @@
|
|
1
1
|
import Router from 'express-promise-router';
|
2
2
|
import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
3
3
|
import { corsHandler } from '../middleware/cors';
|
4
|
-
import { storageService } from
|
4
|
+
import { storageService } from '../storageService';
|
5
5
|
const router = Router();
|
6
6
|
const api = new KapetaAPI();
|
7
7
|
const DEFAULT_REGISTRY_BASE = 'https://registry.kapeta.com';
|
@@ -15,21 +15,21 @@ router.put('/:handle/:name', async (req, res) => {
|
|
15
15
|
if (!req.headers['content-type']) {
|
16
16
|
res.status(400).send({
|
17
17
|
status: 400,
|
18
|
-
error: 'Missing content-type header'
|
18
|
+
error: 'Missing content-type header',
|
19
19
|
});
|
20
20
|
return;
|
21
21
|
}
|
22
22
|
if (!req.headers['content-length']) {
|
23
23
|
res.status(400).send({
|
24
24
|
status: 400,
|
25
|
-
error: 'Missing content-length header'
|
25
|
+
error: 'Missing content-length header',
|
26
26
|
});
|
27
27
|
return;
|
28
28
|
}
|
29
29
|
if (!req.headers['content-disposition']) {
|
30
30
|
res.status(400).send({
|
31
31
|
status: 400,
|
32
|
-
error: 'Missing content-disposition header'
|
32
|
+
error: 'Missing content-disposition header',
|
33
33
|
});
|
34
34
|
return;
|
35
35
|
}
|
@@ -45,7 +45,7 @@ router.put('/:handle/:name', async (req, res) => {
|
|
45
45
|
'content-length': req.headers['content-length'],
|
46
46
|
'content-disposition': req.headers['content-disposition'],
|
47
47
|
},
|
48
|
-
body: req
|
48
|
+
body: req,
|
49
49
|
});
|
50
50
|
res.send(result);
|
51
51
|
}
|
@@ -30,6 +30,7 @@ declare class ContainerManager {
|
|
30
30
|
private _version;
|
31
31
|
constructor();
|
32
32
|
initialize(): Promise<void>;
|
33
|
+
checkAlive(): Promise<boolean>;
|
33
34
|
isAlive(): boolean;
|
34
35
|
getMountPoint(kind: string, mountName: string): string;
|
35
36
|
createMounts(kind: string, mountOpts: StringMap): StringMap;
|
@@ -71,6 +71,25 @@ class ContainerManager {
|
|
71
71
|
}
|
72
72
|
throw new Error('Could not connect to docker daemon. Please make sure docker is running and working.');
|
73
73
|
}
|
74
|
+
async checkAlive() {
|
75
|
+
if (!this._docker) {
|
76
|
+
try {
|
77
|
+
await this.initialize();
|
78
|
+
}
|
79
|
+
catch (e) {
|
80
|
+
this._alive = false;
|
81
|
+
}
|
82
|
+
return this._alive;
|
83
|
+
}
|
84
|
+
try {
|
85
|
+
await this._docker.ping();
|
86
|
+
this._alive = true;
|
87
|
+
}
|
88
|
+
catch (e) {
|
89
|
+
this._alive = false;
|
90
|
+
}
|
91
|
+
return this._alive;
|
92
|
+
}
|
74
93
|
isAlive() {
|
75
94
|
return this._alive;
|
76
95
|
}
|
@@ -8,10 +8,12 @@ export class SocketManager {
|
|
8
8
|
return this;
|
9
9
|
}
|
10
10
|
setIo(io) {
|
11
|
-
console.log('Socket server ready');
|
12
11
|
this._io = io;
|
13
12
|
this._bindIO();
|
14
13
|
}
|
14
|
+
isAlive() {
|
15
|
+
return !!this._io;
|
16
|
+
}
|
15
17
|
get io() {
|
16
18
|
if (!this._io) {
|
17
19
|
throw new Error('Socket server not ready');
|
@@ -31,11 +33,9 @@ export class SocketManager {
|
|
31
33
|
_bindSocket(socket) {
|
32
34
|
socket.on('disconnect', () => this._handleSocketDestroyed(socket));
|
33
35
|
socket.on('join', (id) => {
|
34
|
-
console.log('socket joined ', id);
|
35
36
|
socket.join(id);
|
36
37
|
});
|
37
38
|
socket.on('leave', (id) => {
|
38
|
-
console.log('socket left ', id);
|
39
39
|
socket.leave(id);
|
40
40
|
});
|
41
41
|
}
|
@@ -311,9 +311,7 @@ export class BlockInstanceRunner {
|
|
311
311
|
...Object.entries(env).map(([key, value]) => `${key}=${value}`),
|
312
312
|
],
|
313
313
|
HostConfig: {
|
314
|
-
Binds: [
|
315
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
316
|
-
],
|
314
|
+
Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
|
317
315
|
},
|
318
316
|
});
|
319
317
|
try {
|
@@ -19,7 +19,7 @@ export function isLinux() {
|
|
19
19
|
return !isWindows() && !isMac();
|
20
20
|
}
|
21
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.
|
22
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
23
23
|
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
24
24
|
return isLinux() ? '0.0.0.0' : preferredHost;
|
25
25
|
}
|
package/dist/esm/start.js
CHANGED
package/index.ts
CHANGED
@@ -17,6 +17,7 @@ import AssetsRoutes from './src/assets/routes';
|
|
17
17
|
import ProviderRoutes from './src/providers/routes';
|
18
18
|
import AttachmentRoutes from './src/attachments/routes';
|
19
19
|
import { getBindHost } from './src/utils/utils';
|
20
|
+
import request from 'request';
|
20
21
|
|
21
22
|
export type LocalClusterService = HTTP.Server & { host?: string; port?: number };
|
22
23
|
|
@@ -35,13 +36,28 @@ function createServer() {
|
|
35
36
|
app.use('/assets', AssetsRoutes);
|
36
37
|
app.use('/providers', ProviderRoutes);
|
37
38
|
app.use('/attachments', AttachmentRoutes);
|
39
|
+
app.get('/status', async (req, res) => {
|
40
|
+
res.send({
|
41
|
+
ok: true,
|
42
|
+
dockerStatus: await containerManager.checkAlive(),
|
43
|
+
socketStatus: socketManager.isAlive(),
|
44
|
+
});
|
45
|
+
});
|
46
|
+
|
47
|
+
app.get('/ping', async (req, res) => {
|
48
|
+
res.send({
|
49
|
+
ok: true,
|
50
|
+
});
|
51
|
+
});
|
52
|
+
|
38
53
|
app.use('/', (req: express.Request, res: express.Response) => {
|
39
54
|
console.error('Invalid request: %s %s', req.method, req.originalUrl);
|
40
55
|
res.status(400).send({
|
41
56
|
ok: false,
|
42
|
-
error: 'Unknown'
|
57
|
+
error: 'Unknown',
|
43
58
|
});
|
44
59
|
});
|
60
|
+
|
45
61
|
const server = HTTP.createServer(app);
|
46
62
|
|
47
63
|
//socket
|
@@ -68,6 +84,19 @@ export default {
|
|
68
84
|
return currentServer.port;
|
69
85
|
},
|
70
86
|
|
87
|
+
ping: async function (host: string, port: number): Promise<{ ok: boolean }> {
|
88
|
+
return new Promise((resolve, reject) => {
|
89
|
+
request.get(`http://${host}:${port}/ping`, (err, res, body) => {
|
90
|
+
if (err) {
|
91
|
+
reject(err);
|
92
|
+
return;
|
93
|
+
}
|
94
|
+
|
95
|
+
resolve(JSON.parse(body));
|
96
|
+
});
|
97
|
+
});
|
98
|
+
},
|
99
|
+
|
71
100
|
/**
|
72
101
|
* Starts the local cluster service.
|
73
102
|
* resolves when listening is done with port number. Rejects if listening failed.
|
@@ -95,6 +124,17 @@ export default {
|
|
95
124
|
clusterService.setClusterServiceHost(clusterHost);
|
96
125
|
}
|
97
126
|
|
127
|
+
let pingResult = undefined;
|
128
|
+
try {
|
129
|
+
pingResult = await this.ping(clusterHost, clusterPort);
|
130
|
+
} catch (e: any) {
|
131
|
+
//Ignore - expected to not be running since we're starting it
|
132
|
+
}
|
133
|
+
|
134
|
+
if (pingResult?.ok) {
|
135
|
+
throw new Error(`Cluster service already running on: ${clusterHost}:${clusterPort}.`);
|
136
|
+
}
|
137
|
+
|
98
138
|
await clusterService.init();
|
99
139
|
|
100
140
|
currentServer = createServer();
|
@@ -126,7 +166,9 @@ export default {
|
|
126
166
|
|
127
167
|
const bindHost = getBindHost(host);
|
128
168
|
|
129
|
-
currentServer.listen(port, bindHost, () =>
|
169
|
+
currentServer.listen(port, bindHost, () =>
|
170
|
+
resolve({ host, port, dockerStatus: containerManager.isAlive() })
|
171
|
+
);
|
130
172
|
currentServer.host = host;
|
131
173
|
currentServer.port = port;
|
132
174
|
});
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@kapeta/local-cluster-service",
|
3
|
-
"version": "0.8.
|
3
|
+
"version": "0.8.3",
|
4
4
|
"description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
|
5
5
|
"type": "commonjs",
|
6
6
|
"exports": {
|
@@ -31,7 +31,7 @@
|
|
31
31
|
},
|
32
32
|
"scripts": {
|
33
33
|
"start": "node ./dist/cjs/start.js",
|
34
|
-
"dev": "nodemon -e js,ts,json
|
34
|
+
"dev": "nodemon -e js,ts,json ./start.ts",
|
35
35
|
"test": "echo its fine",
|
36
36
|
"clean": "rm -rf ./dist",
|
37
37
|
"build:esm": "tsc --module esnext --outDir ./dist/esm && echo '{\"type\":\"module\"}' > ./dist/esm/package.json",
|
@@ -63,7 +63,6 @@
|
|
63
63
|
"request": "2.88.2",
|
64
64
|
"request-promise": "4.2.6",
|
65
65
|
"socket.io": "^4.5.2",
|
66
|
-
"ts-node": "^10.9.1",
|
67
66
|
"typescript": "^5.1.6",
|
68
67
|
"yaml": "^1.6.0"
|
69
68
|
},
|
@@ -79,7 +78,8 @@
|
|
79
78
|
"eslint": "^8.42.0",
|
80
79
|
"eslint-config-prettier": "^8.8.0",
|
81
80
|
"nodemon": "^2.0.2",
|
82
|
-
"prettier": "^2.8.8"
|
81
|
+
"prettier": "^2.8.8",
|
82
|
+
"ts-node": "^10.9.1"
|
83
83
|
},
|
84
84
|
"prettier": "@kapeta/prettier-config",
|
85
85
|
"release": {
|
@@ -3,7 +3,7 @@ import { KapetaAPI } from '@kapeta/nodejs-api-client';
|
|
3
3
|
|
4
4
|
import { corsHandler } from '../middleware/cors';
|
5
5
|
import { Request, Response } from 'express';
|
6
|
-
import {storageService} from
|
6
|
+
import { storageService } from '../storageService';
|
7
7
|
|
8
8
|
const router = Router();
|
9
9
|
const api = new KapetaAPI();
|
@@ -22,7 +22,7 @@ router.put('/:handle/:name', async (req: Request, res: Response) => {
|
|
22
22
|
if (!req.headers['content-type']) {
|
23
23
|
res.status(400).send({
|
24
24
|
status: 400,
|
25
|
-
error: 'Missing content-type header'
|
25
|
+
error: 'Missing content-type header',
|
26
26
|
});
|
27
27
|
return;
|
28
28
|
}
|
@@ -30,7 +30,7 @@ router.put('/:handle/:name', async (req: Request, res: Response) => {
|
|
30
30
|
if (!req.headers['content-length']) {
|
31
31
|
res.status(400).send({
|
32
32
|
status: 400,
|
33
|
-
error: 'Missing content-length header'
|
33
|
+
error: 'Missing content-length header',
|
34
34
|
});
|
35
35
|
return;
|
36
36
|
}
|
@@ -38,15 +38,15 @@ router.put('/:handle/:name', async (req: Request, res: Response) => {
|
|
38
38
|
if (!req.headers['content-disposition']) {
|
39
39
|
res.status(400).send({
|
40
40
|
status: 400,
|
41
|
-
error: 'Missing content-disposition header'
|
41
|
+
error: 'Missing content-disposition header',
|
42
42
|
});
|
43
43
|
return;
|
44
44
|
}
|
45
45
|
|
46
46
|
try {
|
47
|
-
const {handle, name} = req.params;
|
47
|
+
const { handle, name } = req.params;
|
48
48
|
const url = `${endpoint}/${handle}/${name}/attachments`;
|
49
|
-
const result = await api.send<{url:string}>({
|
49
|
+
const result = await api.send<{ url: string }>({
|
50
50
|
method: 'PUT',
|
51
51
|
url,
|
52
52
|
auth: true,
|
@@ -55,10 +55,10 @@ router.put('/:handle/:name', async (req: Request, res: Response) => {
|
|
55
55
|
'content-length': req.headers['content-length'],
|
56
56
|
'content-disposition': req.headers['content-disposition'],
|
57
57
|
},
|
58
|
-
body: req
|
58
|
+
body: req,
|
59
59
|
});
|
60
60
|
res.send(result);
|
61
|
-
} catch (e:any) {
|
61
|
+
} catch (e: any) {
|
62
62
|
res.status(e.status ?? 500).send(e);
|
63
63
|
}
|
64
64
|
});
|
package/src/containerManager.ts
CHANGED
@@ -105,6 +105,26 @@ class ContainerManager {
|
|
105
105
|
throw new Error('Could not connect to docker daemon. Please make sure docker is running and working.');
|
106
106
|
}
|
107
107
|
|
108
|
+
async checkAlive() {
|
109
|
+
if (!this._docker) {
|
110
|
+
try {
|
111
|
+
await this.initialize();
|
112
|
+
} catch (e) {
|
113
|
+
this._alive = false;
|
114
|
+
}
|
115
|
+
return this._alive;
|
116
|
+
}
|
117
|
+
|
118
|
+
try {
|
119
|
+
await this._docker.ping();
|
120
|
+
this._alive = true;
|
121
|
+
} catch (e) {
|
122
|
+
this._alive = false;
|
123
|
+
}
|
124
|
+
|
125
|
+
return this._alive;
|
126
|
+
}
|
127
|
+
|
108
128
|
isAlive() {
|
109
129
|
return this._alive;
|
110
130
|
}
|
package/src/identities/routes.ts
CHANGED
@@ -12,16 +12,15 @@ router.use('/', corsHandler);
|
|
12
12
|
router.get('/current', async (req: Request, res: Response) => {
|
13
13
|
try {
|
14
14
|
res.send(await api.getCurrentIdentity());
|
15
|
-
} catch (e:any) {
|
15
|
+
} catch (e: any) {
|
16
16
|
res.status(e.status ?? 500).send(e);
|
17
17
|
}
|
18
|
-
|
19
18
|
});
|
20
19
|
|
21
20
|
router.get('/:identityId/memberships', async (req: Request, res: Response) => {
|
22
21
|
try {
|
23
22
|
res.send(await api.getMemberships(req.params.identityId));
|
24
|
-
} catch (e:any) {
|
23
|
+
} catch (e: any) {
|
25
24
|
res.status(e.status ?? 500).send(e);
|
26
25
|
}
|
27
26
|
});
|
package/src/repositoryManager.ts
CHANGED
@@ -41,23 +41,23 @@ class RepositoryManager {
|
|
41
41
|
|
42
42
|
console.log('Watching local repository for provider changes: %s', baseDir);
|
43
43
|
try {
|
44
|
-
this.watcher = watch(baseDir, (filename:string) => {
|
44
|
+
this.watcher = watch(baseDir, (filename: string) => {
|
45
45
|
if (!filename) {
|
46
46
|
return;
|
47
47
|
}
|
48
|
-
|
48
|
+
|
49
49
|
const [handle, name, version] = filename.toString().split(/\//g);
|
50
50
|
if (!name || !version) {
|
51
51
|
return;
|
52
52
|
}
|
53
|
-
|
53
|
+
|
54
54
|
if (!this.changeEventsEnabled) {
|
55
55
|
return;
|
56
56
|
}
|
57
|
-
|
57
|
+
|
58
58
|
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
59
59
|
const newDefinitions = ClusterConfiguration.getDefinitions();
|
60
|
-
|
60
|
+
|
61
61
|
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
62
62
|
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
63
63
|
const ymlExists = FS.existsSync(ymlPath);
|
@@ -85,13 +85,13 @@ class RepositoryManager {
|
|
85
85
|
return;
|
86
86
|
}
|
87
87
|
}
|
88
|
-
|
88
|
+
|
89
89
|
const payload = {
|
90
90
|
type,
|
91
91
|
definition: currentDefinition?.definition,
|
92
92
|
asset: { handle, name, version },
|
93
93
|
};
|
94
|
-
|
94
|
+
|
95
95
|
allDefinitions = newDefinitions;
|
96
96
|
socketManager.emit(`assets`, 'changed', payload);
|
97
97
|
});
|
package/src/socketManager.ts
CHANGED
@@ -12,12 +12,14 @@ export class SocketManager {
|
|
12
12
|
}
|
13
13
|
|
14
14
|
setIo(io: Server) {
|
15
|
-
console.log('Socket server ready');
|
16
15
|
this._io = io;
|
17
|
-
|
18
16
|
this._bindIO();
|
19
17
|
}
|
20
18
|
|
19
|
+
isAlive() {
|
20
|
+
return !!this._io;
|
21
|
+
}
|
22
|
+
|
21
23
|
private get io() {
|
22
24
|
if (!this._io) {
|
23
25
|
throw new Error('Socket server not ready');
|
@@ -41,11 +43,9 @@ export class SocketManager {
|
|
41
43
|
_bindSocket(socket: Socket) {
|
42
44
|
socket.on('disconnect', () => this._handleSocketDestroyed(socket));
|
43
45
|
socket.on('join', (id) => {
|
44
|
-
console.log('socket joined ', id);
|
45
46
|
socket.join(id);
|
46
47
|
});
|
47
48
|
socket.on('leave', (id) => {
|
48
|
-
console.log('socket left ', id);
|
49
49
|
socket.leave(id);
|
50
50
|
});
|
51
51
|
}
|
package/src/storageService.ts
CHANGED
@@ -53,7 +53,7 @@ class StorageService {
|
|
53
53
|
this._writeConfig();
|
54
54
|
}
|
55
55
|
|
56
|
-
get<T = any>(section: string, property?: string, defaultValue?:T): T|undefined {
|
56
|
+
get<T = any>(section: string, property?: string, defaultValue?: T): T | undefined {
|
57
57
|
if (!property) {
|
58
58
|
return this.section(section);
|
59
59
|
}
|
@@ -216,7 +216,7 @@ export class BlockInstanceRunner {
|
|
216
216
|
|
217
217
|
PortBindings[dockerPort] = [
|
218
218
|
{
|
219
|
-
HostIp: bindHost,
|
219
|
+
HostIp: bindHost,
|
220
220
|
HostPort: `${publicPort}`,
|
221
221
|
},
|
222
222
|
];
|
@@ -380,9 +380,7 @@ export class BlockInstanceRunner {
|
|
380
380
|
...Object.entries(env).map(([key, value]) => `${key}=${value}`),
|
381
381
|
],
|
382
382
|
HostConfig: {
|
383
|
-
Binds: [
|
384
|
-
`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`,
|
385
|
-
],
|
383
|
+
Binds: [`${toLocalBindVolume(ClusterConfig.getKapetaBasedir())}:${innerHome}`],
|
386
384
|
},
|
387
385
|
});
|
388
386
|
|
package/src/utils/utils.ts
CHANGED
@@ -24,7 +24,7 @@ export function isLinux() {
|
|
24
24
|
}
|
25
25
|
|
26
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.
|
27
|
+
// On Linux we need to bind to 0.0.0.0 to be able to connect to it from docker containers.
|
28
28
|
// TODO: This might pose a security risk - so we should authenticate all requests using a shared secret/nonce that we pass around.
|
29
29
|
return isLinux() ? '0.0.0.0' : preferredHost;
|
30
|
-
}
|
30
|
+
}
|