@milaboratories/pl-deployments 1.1.10 → 1.1.11
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/dist/common/pl_binary.d.ts.map +1 -1
- package/dist/index.js +8 -8
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +479 -421
- package/dist/index.mjs.map +1 -1
- package/dist/ssh/__tests__/common-utils.d.ts.map +1 -1
- package/dist/ssh/connection_info.d.ts +266 -0
- package/dist/ssh/connection_info.d.ts.map +1 -0
- package/dist/ssh/pl.d.ts +26 -37
- package/dist/ssh/pl.d.ts.map +1 -1
- package/dist/ssh/pl_paths.d.ts +1 -0
- package/dist/ssh/pl_paths.d.ts.map +1 -1
- package/dist/ssh/ssh.d.ts +0 -1
- package/dist/ssh/ssh.d.ts.map +1 -1
- package/dist/ssh/supervisord.d.ts +11 -2
- package/dist/ssh/supervisord.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/common/pl_binary.ts +2 -1
- package/src/ssh/__tests__/common-utils.ts +5 -3
- package/src/ssh/__tests__/pl-docker.test.ts +33 -14
- package/src/ssh/__tests__/ssh-docker.test.ts +1 -1
- package/src/ssh/connection_info.ts +62 -0
- package/src/ssh/pl.ts +78 -76
- package/src/ssh/pl_paths.ts +6 -2
- package/src/ssh/ssh.ts +8 -10
- package/src/ssh/supervisord.ts +26 -12
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** We store all info about the connection on the server,
|
|
2
|
+
* so that another client could read the file and connect from another machine. */
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
|
|
5
|
+
//
|
|
6
|
+
// Types
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
export const PortPair = z.object({
|
|
10
|
+
local: z.number(),
|
|
11
|
+
remote: z.number(),
|
|
12
|
+
});
|
|
13
|
+
/** The pair of ports for forwarding. */
|
|
14
|
+
export type PortPair = z.infer<typeof PortPair>;
|
|
15
|
+
|
|
16
|
+
export const SshPlPorts = z.object({
|
|
17
|
+
grpc: PortPair,
|
|
18
|
+
monitoring: PortPair,
|
|
19
|
+
debug: PortPair,
|
|
20
|
+
minioPort: PortPair,
|
|
21
|
+
minioConsolePort: PortPair,
|
|
22
|
+
});
|
|
23
|
+
/** All info about ports that are forwarded. */
|
|
24
|
+
export type SshPlPorts = z.infer<typeof SshPlPorts>;
|
|
25
|
+
|
|
26
|
+
export const ConnectionInfo = z.object({
|
|
27
|
+
plUser: z.string(),
|
|
28
|
+
plPassword: z.string(),
|
|
29
|
+
ports: SshPlPorts,
|
|
30
|
+
|
|
31
|
+
// It's false by default because it was added later,
|
|
32
|
+
// and in some deployments there won't be useGlobalAccess flag in the file.
|
|
33
|
+
useGlobalAccess: z.boolean().default(false),
|
|
34
|
+
});
|
|
35
|
+
/** The content of the file that holds all the info about the connection on the remote server. */
|
|
36
|
+
export type ConnectionInfo = z.infer<typeof ConnectionInfo>;
|
|
37
|
+
|
|
38
|
+
//
|
|
39
|
+
// Funcs
|
|
40
|
+
//
|
|
41
|
+
|
|
42
|
+
export function newConnectionInfo(
|
|
43
|
+
plUser: string,
|
|
44
|
+
plPassword: string,
|
|
45
|
+
ports: SshPlPorts,
|
|
46
|
+
useGlobalAccess: boolean,
|
|
47
|
+
): ConnectionInfo {
|
|
48
|
+
return {
|
|
49
|
+
plUser,
|
|
50
|
+
plPassword,
|
|
51
|
+
ports,
|
|
52
|
+
useGlobalAccess,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function parseConnectionInfo(content: string): ConnectionInfo {
|
|
57
|
+
return ConnectionInfo.parse(JSON.parse(content));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function stringifyConnectionInfo(conn: ConnectionInfo): string {
|
|
61
|
+
return JSON.stringify(conn, undefined, 2);
|
|
62
|
+
}
|
package/src/ssh/pl.ts
CHANGED
|
@@ -11,7 +11,10 @@ import { getDefaultPlVersion } from '../common/pl_version';
|
|
|
11
11
|
import net from 'net';
|
|
12
12
|
import type { PlLicenseMode, SshPlConfigGenerationResult } from '@milaboratories/pl-config';
|
|
13
13
|
import { generateSshPlConfigs, getFreePort } from '@milaboratories/pl-config';
|
|
14
|
+
import type { SupervisorStatus } from './supervisord';
|
|
14
15
|
import { supervisorStatus, supervisorStop as supervisorCtlShutdown, generateSupervisordConfig, supervisorCtlStart } from './supervisord';
|
|
16
|
+
import type { ConnectionInfo, SshPlPorts } from './connection_info';
|
|
17
|
+
import { newConnectionInfo, parseConnectionInfo, stringifyConnectionInfo } from './connection_info';
|
|
15
18
|
|
|
16
19
|
export class SshPl {
|
|
17
20
|
private initState: PlatformaInitState = {};
|
|
@@ -42,49 +45,60 @@ export class SshPl {
|
|
|
42
45
|
this.sshClient.close();
|
|
43
46
|
}
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
/** Provides an info if the platforma and minio are running along with the debug info. */
|
|
49
|
+
public async isAlive(): Promise<SupervisorStatus> {
|
|
46
50
|
const arch = await this.getArch();
|
|
47
51
|
const remoteHome = await this.getUserHomeDirectory();
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
return await supervisorStatus(this.logger, this.sshClient, remoteHome, arch.arch);
|
|
51
|
-
} catch (e: unknown) {
|
|
52
|
-
// probably there are no supervisor on the server.
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
52
|
+
return await supervisorStatus(this.logger, this.sshClient, remoteHome, arch.arch);
|
|
55
53
|
}
|
|
56
54
|
|
|
55
|
+
/** Starts all the services on the server.
|
|
56
|
+
* Idempotent semantic: we could call it several times. */
|
|
57
57
|
public async start() {
|
|
58
58
|
const arch = await this.getArch();
|
|
59
59
|
const remoteHome = await this.getUserHomeDirectory();
|
|
60
60
|
|
|
61
61
|
try {
|
|
62
|
-
await
|
|
62
|
+
if (!(await this.isAlive()).allAlive) {
|
|
63
|
+
await supervisorCtlStart(this.sshClient, remoteHome, arch.arch);
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
// We are waiting for Platforma to run to ensure that it has started.
|
|
66
|
+
return await this.checkIsAliveWithInterval();
|
|
67
|
+
}
|
|
66
68
|
} catch (e: unknown) {
|
|
67
|
-
const msg = `
|
|
69
|
+
const msg = `SshPl.start: error occurred ${e}`;
|
|
68
70
|
this.logger.error(msg);
|
|
69
71
|
throw new Error(msg);
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
|
|
75
|
+
/** Stops all the services on the server.
|
|
76
|
+
* Idempotent semantic: we could call it several times. */
|
|
73
77
|
public async stop() {
|
|
74
78
|
const arch = await this.getArch();
|
|
75
79
|
const remoteHome = await this.getUserHomeDirectory();
|
|
76
80
|
|
|
77
81
|
try {
|
|
78
|
-
await
|
|
79
|
-
|
|
82
|
+
if ((await this.isAlive()).allAlive) {
|
|
83
|
+
await supervisorCtlShutdown(this.sshClient, remoteHome, arch.arch);
|
|
84
|
+
return await this.checkIsAliveWithInterval(undefined, undefined, false);
|
|
85
|
+
}
|
|
80
86
|
} catch (e: unknown) {
|
|
81
|
-
const msg = `
|
|
87
|
+
const msg = `PlSsh.stop: error occurred ${e}`;
|
|
82
88
|
this.logger.error(msg);
|
|
83
89
|
throw new Error(msg);
|
|
84
90
|
}
|
|
85
91
|
}
|
|
86
92
|
|
|
93
|
+
/** Stops the services, deletes a directory with the state and closes SSH connection. */
|
|
87
94
|
public async reset(): Promise<boolean> {
|
|
95
|
+
await this.stopAndClean();
|
|
96
|
+
this.cleanUp();
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** Stops platforma and deletes its state. */
|
|
101
|
+
public async stopAndClean(): Promise<void> {
|
|
88
102
|
const workDir = await this.getUserHomeDirectory();
|
|
89
103
|
|
|
90
104
|
this.logger.info(`pl.reset: Stop Platforma on the server`);
|
|
@@ -92,26 +106,35 @@ export class SshPl {
|
|
|
92
106
|
|
|
93
107
|
this.logger.info(`pl.reset: Deleting Platforma workDir ${workDir} on the server`);
|
|
94
108
|
await this.sshClient.deleteFolder(plpath.workDir(workDir));
|
|
95
|
-
|
|
96
|
-
this.cleanUp();
|
|
97
|
-
|
|
98
|
-
return true;
|
|
99
109
|
}
|
|
100
110
|
|
|
101
|
-
|
|
102
|
-
|
|
111
|
+
/** Downloads binaries and untar them on the server,
|
|
112
|
+
* generates all the configs, creates necessary dirs,
|
|
113
|
+
* and finally starts all the services. */
|
|
114
|
+
public async platformaInit(options: SshPlConfig): Promise<ConnectionInfo> {
|
|
115
|
+
const state: PlatformaInitState = { localWorkdir: options.localWorkdir };
|
|
103
116
|
|
|
104
117
|
try {
|
|
118
|
+
// merge options with default ops.
|
|
119
|
+
const ops: SshPlConfig = {
|
|
120
|
+
...defaultSshPlConfig,
|
|
121
|
+
...options,
|
|
122
|
+
};
|
|
105
123
|
state.arch = await this.getArch();
|
|
106
124
|
state.remoteHome = await this.getUserHomeDirectory();
|
|
107
|
-
state.
|
|
125
|
+
state.alive = await this.isAlive();
|
|
108
126
|
|
|
109
|
-
if (state.
|
|
127
|
+
if (state.alive.allAlive) {
|
|
110
128
|
state.userCredentials = await this.getUserCredentials(state.remoteHome);
|
|
111
129
|
if (!state.userCredentials) {
|
|
112
130
|
throw new Error(`SshPl.platformaInit: platforma is alive but userCredentials are not found`);
|
|
113
131
|
}
|
|
114
|
-
|
|
132
|
+
const needRestart = state.userCredentials.useGlobalAccess != ops.useGlobalAccess;
|
|
133
|
+
if (!needRestart)
|
|
134
|
+
return state.userCredentials;
|
|
135
|
+
|
|
136
|
+
// make sure that we won't be in a broken state.
|
|
137
|
+
await this.stopAndClean();
|
|
115
138
|
}
|
|
116
139
|
|
|
117
140
|
const downloadRes = await this.downloadBinariesAndUploadToTheServer(
|
|
@@ -143,6 +166,7 @@ export class SshPl {
|
|
|
143
166
|
},
|
|
144
167
|
},
|
|
145
168
|
licenseMode: ops.license,
|
|
169
|
+
useGlobalAccess: notEmpty(ops.useGlobalAccess),
|
|
146
170
|
});
|
|
147
171
|
state.generatedConfig = { ...config, filesToCreate: { skipped: 'it is too wordy' } };
|
|
148
172
|
|
|
@@ -171,25 +195,22 @@ export class SshPl {
|
|
|
171
195
|
throw new Error(`Can not write supervisord config on the server ${plpath.workDir(state.remoteHome)}`);
|
|
172
196
|
}
|
|
173
197
|
|
|
174
|
-
state.connectionInfo =
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
198
|
+
state.connectionInfo = newConnectionInfo(
|
|
199
|
+
config.plUser,
|
|
200
|
+
config.plPassword,
|
|
201
|
+
state.ports,
|
|
202
|
+
notEmpty(ops.useGlobalAccess),
|
|
203
|
+
);
|
|
179
204
|
await this.sshClient.writeFileOnTheServer(
|
|
180
205
|
plpath.connectionInfo(state.remoteHome),
|
|
181
|
-
|
|
206
|
+
stringifyConnectionInfo(state.connectionInfo),
|
|
182
207
|
);
|
|
183
208
|
|
|
184
209
|
await this.start();
|
|
185
210
|
state.started = true;
|
|
186
211
|
this.initState = state;
|
|
187
212
|
|
|
188
|
-
return
|
|
189
|
-
plUser: config.plUser,
|
|
190
|
-
plPassword: config.plPassword,
|
|
191
|
-
ports: state.ports,
|
|
192
|
-
};
|
|
213
|
+
return state.connectionInfo;
|
|
193
214
|
} catch (e: unknown) {
|
|
194
215
|
const msg = `SshPl.platformaInit: error occurred: ${e}, state: ${JSON.stringify(state)}`;
|
|
195
216
|
this.logger.error(msg);
|
|
@@ -239,8 +260,10 @@ export class SshPl {
|
|
|
239
260
|
|
|
240
261
|
/** We have to extract pl in the remote server,
|
|
241
262
|
* because Windows doesn't support symlinks
|
|
242
|
-
* that are found in
|
|
243
|
-
* For this reason, we extract all to the remote server.
|
|
263
|
+
* that are found in Linux pl binaries tgz archive.
|
|
264
|
+
* For this reason, we extract all to the remote server.
|
|
265
|
+
* It requires `tar` to be installed on the server
|
|
266
|
+
* (it's not installed for Rocky Linux for example). */
|
|
244
267
|
public async downloadAndUntar(
|
|
245
268
|
localWorkdir: string,
|
|
246
269
|
remoteHome: string,
|
|
@@ -308,28 +331,28 @@ export class SshPl {
|
|
|
308
331
|
return false;
|
|
309
332
|
}
|
|
310
333
|
|
|
311
|
-
public async checkIsAliveWithInterval(interval: number = 1000, count = 15, shouldStart = true) {
|
|
334
|
+
public async checkIsAliveWithInterval(interval: number = 1000, count = 15, shouldStart = true): Promise<void> {
|
|
312
335
|
const maxMs = count * interval;
|
|
313
336
|
|
|
314
337
|
let total = 0;
|
|
315
338
|
let alive = await this.isAlive();
|
|
316
|
-
while (shouldStart ? !alive : alive) {
|
|
339
|
+
while (shouldStart ? !alive.allAlive : alive.allAlive) {
|
|
317
340
|
await sleep(interval);
|
|
318
341
|
total += interval;
|
|
319
342
|
if (total > maxMs) {
|
|
320
|
-
throw new Error(`isAliveWithInterval: The process did not ${shouldStart ? 'started' : 'stopped'} after ${maxMs} ms
|
|
343
|
+
throw new Error(`isAliveWithInterval: The process did not ${shouldStart ? 'started' : 'stopped'} after ${maxMs} ms. Live status: ${JSON.stringify(alive)}`);
|
|
321
344
|
}
|
|
322
345
|
alive = await this.isAlive();
|
|
323
346
|
}
|
|
324
347
|
}
|
|
325
348
|
|
|
326
|
-
public async getUserCredentials(remoteHome: string): Promise<
|
|
349
|
+
public async getUserCredentials(remoteHome: string): Promise<ConnectionInfo> {
|
|
327
350
|
const connectionInfo = await this.sshClient.readFile(plpath.connectionInfo(remoteHome));
|
|
328
|
-
return
|
|
351
|
+
return parseConnectionInfo(connectionInfo);
|
|
329
352
|
}
|
|
330
353
|
|
|
331
|
-
public async fetchPorts(remoteHome: string, arch: Arch): Promise<
|
|
332
|
-
const ports:
|
|
354
|
+
public async fetchPorts(remoteHome: string, arch: Arch): Promise<SshPlPorts> {
|
|
355
|
+
const ports: SshPlPorts = {
|
|
333
356
|
grpc: {
|
|
334
357
|
local: await getFreePort(),
|
|
335
358
|
remote: await this.getFreePortForPlatformaOnServer(remoteHome, arch),
|
|
@@ -403,41 +426,20 @@ export class SshPl {
|
|
|
403
426
|
}
|
|
404
427
|
}
|
|
405
428
|
|
|
406
|
-
export type SshPlatformaPorts = {
|
|
407
|
-
grpc: {
|
|
408
|
-
local: number;
|
|
409
|
-
remote: number;
|
|
410
|
-
};
|
|
411
|
-
monitoring: {
|
|
412
|
-
local: number;
|
|
413
|
-
remote: number;
|
|
414
|
-
};
|
|
415
|
-
debug: {
|
|
416
|
-
local: number;
|
|
417
|
-
remote: number;
|
|
418
|
-
};
|
|
419
|
-
minioPort: {
|
|
420
|
-
local: number;
|
|
421
|
-
remote: number;
|
|
422
|
-
};
|
|
423
|
-
minioConsolePort: {
|
|
424
|
-
local: number;
|
|
425
|
-
remote: number;
|
|
426
|
-
};
|
|
427
|
-
};
|
|
428
|
-
|
|
429
429
|
type Arch = { platform: string; arch: string };
|
|
430
430
|
|
|
431
431
|
export type SshPlConfig = {
|
|
432
432
|
localWorkdir: string;
|
|
433
433
|
license: PlLicenseMode;
|
|
434
|
+
useGlobalAccess?: boolean;
|
|
434
435
|
};
|
|
435
436
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
437
|
+
const defaultSshPlConfig: Pick<
|
|
438
|
+
SshPlConfig,
|
|
439
|
+
'useGlobalAccess'
|
|
440
|
+
> = {
|
|
441
|
+
useGlobalAccess: false,
|
|
442
|
+
};
|
|
441
443
|
|
|
442
444
|
type BinPaths = {
|
|
443
445
|
history?: DownloadAndUntarState[];
|
|
@@ -462,12 +464,12 @@ type PlatformaInitState = {
|
|
|
462
464
|
localWorkdir?: string;
|
|
463
465
|
arch?: Arch;
|
|
464
466
|
remoteHome?: string;
|
|
465
|
-
|
|
466
|
-
userCredentials?:
|
|
467
|
+
alive?: SupervisorStatus;
|
|
468
|
+
userCredentials?: ConnectionInfo;
|
|
467
469
|
downloadedBinaries?: DownloadAndUntarState[];
|
|
468
470
|
binPaths?: BinPaths;
|
|
469
|
-
ports?:
|
|
471
|
+
ports?: SshPlPorts;
|
|
470
472
|
generatedConfig?: SshPlConfigGenerationResult;
|
|
471
|
-
connectionInfo?:
|
|
473
|
+
connectionInfo?: ConnectionInfo;
|
|
472
474
|
started?: boolean;
|
|
473
475
|
};
|
package/src/ssh/pl_paths.ts
CHANGED
|
@@ -9,11 +9,11 @@ export const supervisordDirName = 'supervisord-0.7.3';
|
|
|
9
9
|
export const supervisordSubDirName = 'supervisord_0.7.3_Linux_64-bit';
|
|
10
10
|
|
|
11
11
|
export function workDir(remoteHome: string) {
|
|
12
|
-
return upath.join(remoteHome, 'platforma_ssh');
|
|
12
|
+
return upath.join(remoteHome, '.platforma_ssh');
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function binariesDir(remoteHome: string) {
|
|
16
|
-
return upath.join(remoteHome, '
|
|
16
|
+
return upath.join(workDir(remoteHome), 'binaries');
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function platformaBaseDir(remoteHome: string, arch: string) {
|
|
@@ -28,6 +28,10 @@ export function platformaBin(remoteHome: string, arch: string) {
|
|
|
28
28
|
return upath.join(platformaDir(remoteHome, arch), 'platforma');
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
export function platformaConf(remoteHome: string): string {
|
|
32
|
+
return upath.join(workDir(remoteHome), 'config.yaml');
|
|
33
|
+
}
|
|
34
|
+
|
|
31
35
|
export function platformaFreePortBin(remoteHome: string, arch: string): string {
|
|
32
36
|
return upath.join(platformaDir(remoteHome, arch), 'free-port');
|
|
33
37
|
}
|
package/src/ssh/ssh.ts
CHANGED
|
@@ -314,12 +314,6 @@ export class SshClient {
|
|
|
314
314
|
});
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
-
delay(delay: number): Promise<void> {
|
|
318
|
-
return new Promise((res, rej) => {
|
|
319
|
-
setTimeout(() => res(), delay);
|
|
320
|
-
});
|
|
321
|
-
}
|
|
322
|
-
|
|
323
317
|
public async withSftp<R>(callback: (sftp: SFTPWrapper) => Promise<R>): Promise<R> {
|
|
324
318
|
return new Promise((resolve, reject) => {
|
|
325
319
|
this.client.sftp((err, sftp) => {
|
|
@@ -441,9 +435,9 @@ export class SshClient {
|
|
|
441
435
|
async checkFileExists(remotePath: string) {
|
|
442
436
|
return this.withSftp(async (sftp) => {
|
|
443
437
|
return new Promise((resolve, reject) => {
|
|
444
|
-
sftp.stat(remotePath, (err, stats) => {
|
|
438
|
+
sftp.stat(remotePath, (err: Error | undefined, stats) => {
|
|
445
439
|
if (err) {
|
|
446
|
-
if ((err as
|
|
440
|
+
if ((err as unknown as { code?: number })?.code === 2) {
|
|
447
441
|
return resolve(false);
|
|
448
442
|
}
|
|
449
443
|
return reject(new Error(`ssh.checkFileExists: err ${err}`));
|
|
@@ -540,8 +534,12 @@ export class SshClient {
|
|
|
540
534
|
public async uploadDirectory(localDir: string, remoteDir: string, mode: number = 0o660): Promise<void> {
|
|
541
535
|
return new Promise((resolve, reject) => {
|
|
542
536
|
this.withSftp(async (sftp: SFTPWrapper) => {
|
|
543
|
-
|
|
544
|
-
|
|
537
|
+
try {
|
|
538
|
+
await this.__uploadDirectory(sftp, localDir, remoteDir, mode);
|
|
539
|
+
resolve();
|
|
540
|
+
} catch (e: unknown) {
|
|
541
|
+
reject(new Error(`ssh.uploadDirectory: ${e}`));
|
|
542
|
+
}
|
|
545
543
|
});
|
|
546
544
|
});
|
|
547
545
|
}
|
package/src/ssh/supervisord.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import type { MiLogger } from '@milaboratories/ts-helpers';
|
|
4
4
|
import * as plpath from './pl_paths';
|
|
5
|
-
import type { SshClient } from './ssh';
|
|
5
|
+
import type { SshClient, SshExecResult } from './ssh';
|
|
6
6
|
import { randomBytes } from 'crypto';
|
|
7
7
|
|
|
8
8
|
export async function supervisorCtlStart(
|
|
@@ -27,31 +27,45 @@ export async function supervisorStop(
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
/** Provides a simple true/false response got from supervisord status
|
|
31
|
+
* along with a debug info that could be showed in error logs (raw response from the command, parsed response etc). */
|
|
32
|
+
export type SupervisorStatus = {
|
|
33
|
+
platforma?: boolean;
|
|
34
|
+
minio?: boolean;
|
|
35
|
+
allAlive: boolean; // true when both pl and minio are alive.
|
|
36
|
+
rawResult?: SshExecResult;
|
|
37
|
+
execError?: string;
|
|
33
38
|
};
|
|
34
39
|
|
|
35
40
|
export async function supervisorStatus(
|
|
36
41
|
logger: MiLogger,
|
|
37
42
|
sshClient: SshClient,
|
|
38
43
|
remoteHome: string, arch: string,
|
|
39
|
-
): Promise<
|
|
40
|
-
|
|
44
|
+
): Promise<SupervisorStatus> {
|
|
45
|
+
let result: SshExecResult;
|
|
46
|
+
try {
|
|
47
|
+
result = await supervisorExec(sshClient, remoteHome, arch, 'ctl status');
|
|
48
|
+
} catch (e: unknown) {
|
|
49
|
+
return { execError: String(e), allAlive: false };
|
|
50
|
+
}
|
|
41
51
|
|
|
42
52
|
if (result.stderr) {
|
|
43
53
|
logger.info(`supervisord ctl status: stderr occurred: ${result.stderr}, stdout: ${result.stdout}`);
|
|
44
54
|
|
|
45
|
-
return false;
|
|
55
|
+
return { rawResult: result, allAlive: false };
|
|
46
56
|
}
|
|
47
57
|
|
|
58
|
+
const platforma = isProgramRunning(result.stdout, 'platforma');
|
|
59
|
+
const minio = isProgramRunning(result.stdout, 'minio');
|
|
48
60
|
const status: SupervisorStatus = {
|
|
49
|
-
|
|
50
|
-
|
|
61
|
+
rawResult: result,
|
|
62
|
+
platforma,
|
|
63
|
+
minio,
|
|
64
|
+
allAlive: platforma && minio,
|
|
51
65
|
};
|
|
52
66
|
|
|
53
|
-
if (status.
|
|
54
|
-
return
|
|
67
|
+
if (status.allAlive) {
|
|
68
|
+
return status;
|
|
55
69
|
}
|
|
56
70
|
|
|
57
71
|
if (!status.minio) {
|
|
@@ -62,7 +76,7 @@ export async function supervisorStatus(
|
|
|
62
76
|
logger.warn('Platforma is not running on the server');
|
|
63
77
|
}
|
|
64
78
|
|
|
65
|
-
return
|
|
79
|
+
return status;
|
|
66
80
|
}
|
|
67
81
|
|
|
68
82
|
export function generateSupervisordConfig(
|