@milaboratories/pl-deployments 2.3.3 → 2.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +34 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +683 -585
- package/dist/index.mjs.map +1 -1
- package/dist/ssh/connection_info.d.ts +52 -1
- package/dist/ssh/connection_info.d.ts.map +1 -1
- package/dist/ssh/pl.d.ts +22 -7
- package/dist/ssh/pl.d.ts.map +1 -1
- package/dist/ssh/supervisord.d.ts +4 -2
- package/dist/ssh/supervisord.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/ssh/__tests__/pl-docker.test.ts +13 -10
- package/src/ssh/connection_info.ts +8 -0
- package/src/ssh/pl.ts +268 -138
- package/src/ssh/supervisord.ts +47 -8
package/src/ssh/pl.ts
CHANGED
|
@@ -10,9 +10,9 @@ import { getDefaultPlVersion } from '../common/pl_version';
|
|
|
10
10
|
|
|
11
11
|
import net from 'node:net';
|
|
12
12
|
import type { PlConfig, PlLicenseMode, SshPlConfigGenerationResult } from '@milaboratories/pl-config';
|
|
13
|
-
import {
|
|
13
|
+
import { getFreePort, generateSshPlConfigs } from '@milaboratories/pl-config';
|
|
14
14
|
import type { SupervisorStatus } from './supervisord';
|
|
15
|
-
import { supervisorStatus, supervisorStop as supervisorCtlShutdown,
|
|
15
|
+
import { supervisorStatus, supervisorStop as supervisorCtlShutdown, generateSupervisordConfigWithMinio, supervisorCtlStart, isSupervisordRunning, generateSupervisordConfig, isAllAlive } from './supervisord';
|
|
16
16
|
import type { ConnectionInfo, SshPlPorts } from './connection_info';
|
|
17
17
|
import { newConnectionInfo, parseConnectionInfo, stringifyConnectionInfo } from './connection_info';
|
|
18
18
|
import type { PlBinarySourceDownload } from '../common/pl_binary';
|
|
@@ -20,7 +20,7 @@ import type { PlBinarySourceDownload } from '../common/pl_binary';
|
|
|
20
20
|
const minRequiredGlibcVersion = 2.28;
|
|
21
21
|
|
|
22
22
|
export class SshPl {
|
|
23
|
-
private initState: PlatformaInitState = {};
|
|
23
|
+
private initState: PlatformaInitState = { step: 'init' };
|
|
24
24
|
constructor(
|
|
25
25
|
public readonly logger: MiLogger,
|
|
26
26
|
public readonly sshClient: SshClient,
|
|
@@ -57,16 +57,16 @@ export class SshPl {
|
|
|
57
57
|
|
|
58
58
|
/** Starts all the services on the server.
|
|
59
59
|
* Idempotent semantic: we could call it several times. */
|
|
60
|
-
public async start() {
|
|
60
|
+
public async start(shouldUseMinio: boolean) {
|
|
61
61
|
const arch = await this.getArch();
|
|
62
62
|
const remoteHome = await this.getUserHomeDirectory();
|
|
63
63
|
|
|
64
64
|
try {
|
|
65
|
-
if (!(await this.isAlive())
|
|
65
|
+
if (!isAllAlive(await this.isAlive(), shouldUseMinio)) {
|
|
66
66
|
await supervisorCtlStart(this.sshClient, remoteHome, arch.arch);
|
|
67
67
|
|
|
68
68
|
// We are waiting for Platforma to run to ensure that it has started.
|
|
69
|
-
return await this.checkIsAliveWithInterval();
|
|
69
|
+
return await this.checkIsAliveWithInterval(shouldUseMinio);
|
|
70
70
|
}
|
|
71
71
|
} catch (e: unknown) {
|
|
72
72
|
const msg = `SshPl.start: ${e}`;
|
|
@@ -82,9 +82,12 @@ export class SshPl {
|
|
|
82
82
|
const remoteHome = await this.getUserHomeDirectory();
|
|
83
83
|
|
|
84
84
|
try {
|
|
85
|
-
|
|
85
|
+
const alive = await this.isAlive();
|
|
86
|
+
if (isSupervisordRunning(alive)) {
|
|
86
87
|
await supervisorCtlShutdown(this.sshClient, remoteHome, arch.arch);
|
|
87
|
-
|
|
88
|
+
// Check if Minio is running by looking at the alive status
|
|
89
|
+
const shouldUseMinio = alive.minio === true;
|
|
90
|
+
return await this.checkIsAliveWithInterval(shouldUseMinio, 1000, 15, false);
|
|
88
91
|
}
|
|
89
92
|
} catch (e: unknown) {
|
|
90
93
|
const msg = `PlSsh.stop: ${e}`;
|
|
@@ -115,161 +118,266 @@ export class SshPl {
|
|
|
115
118
|
* generates all the configs, creates necessary dirs,
|
|
116
119
|
* and finally starts all the services. */
|
|
117
120
|
public async platformaInit(options: SshPlConfig): Promise<ConnectionInfo> {
|
|
118
|
-
const state: PlatformaInitState = { localWorkdir: options.localWorkdir };
|
|
121
|
+
const state: PlatformaInitState = { localWorkdir: options.localWorkdir, step: 'init' };
|
|
119
122
|
|
|
120
123
|
const { onProgress } = options;
|
|
121
124
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
state.plBinaryOps = ops.plBinary;
|
|
129
|
-
|
|
130
|
-
await onProgress?.('Detecting server architecture...');
|
|
131
|
-
state.arch = await this.getArch();
|
|
132
|
-
await onProgress?.('Server architecture detected.');
|
|
133
|
-
|
|
134
|
-
await onProgress?.('Fetching user home directory...');
|
|
135
|
-
state.remoteHome = await this.getUserHomeDirectory();
|
|
136
|
-
await onProgress?.('User home directory retrieved.');
|
|
125
|
+
// merge options with default ops.
|
|
126
|
+
const ops: SshPlConfig = {
|
|
127
|
+
...defaultSshPlConfig,
|
|
128
|
+
...options,
|
|
129
|
+
};
|
|
130
|
+
state.plBinaryOps = ops.plBinary;
|
|
137
131
|
|
|
138
|
-
|
|
139
|
-
|
|
132
|
+
try {
|
|
133
|
+
await this.doStepDetectArch(state, onProgress);
|
|
134
|
+
await this.doStepDetectHome(state, onProgress);
|
|
140
135
|
|
|
141
|
-
|
|
142
|
-
|
|
136
|
+
const needRestartPlatforma = await this.doStepReadExistedConfig(state, ops, onProgress);
|
|
137
|
+
if (!needRestartPlatforma) {
|
|
138
|
+
await onProgress?.('Platforma is already running. Skipping initialization.');
|
|
139
|
+
return state.existedSettings!;
|
|
143
140
|
}
|
|
141
|
+
await this.doStepStopExistedPlatforma(state, onProgress);
|
|
144
142
|
|
|
145
|
-
|
|
146
|
-
state.userCredentials = await this.getUserCredentials(state.remoteHome);
|
|
147
|
-
if (!state.userCredentials) {
|
|
148
|
-
throw new Error(`SshPl.platformaInit: platforma is alive but userCredentials are not found`);
|
|
149
|
-
}
|
|
150
|
-
const sameGA = state.userCredentials.useGlobalAccess == ops.useGlobalAccess;
|
|
151
|
-
const samePlVersion = state.userCredentials.plVersion == ops.plBinary!.version;
|
|
152
|
-
state.needRestart = !(sameGA && samePlVersion);
|
|
153
|
-
this.logger.info(`SshPl.platformaInit: need restart? ${state.needRestart}`);
|
|
154
|
-
|
|
155
|
-
if (!state.needRestart) {
|
|
156
|
-
await onProgress?.('Server setup completed.');
|
|
157
|
-
return state.userCredentials;
|
|
158
|
-
}
|
|
143
|
+
await onProgress?.('Installation platforma...');
|
|
159
144
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
145
|
+
await this.doStepDownloadBinaries(state, onProgress, ops);
|
|
146
|
+
await this.doStepFetchPorts(state);
|
|
147
|
+
await this.doStepGenerateNewConfig(state, onProgress, ops);
|
|
148
|
+
await this.doStepCreateFoldersAndSaveFiles(state, onProgress);
|
|
149
|
+
await this.doStepConfigureSupervisord(state, onProgress);
|
|
150
|
+
await this.doStepSaveNewConnectionInfo(state, onProgress, ops);
|
|
151
|
+
await this.doStepStartPlatforma(state, onProgress);
|
|
163
152
|
|
|
164
|
-
|
|
153
|
+
return state.connectionInfo!;
|
|
154
|
+
} catch (e: unknown) {
|
|
155
|
+
const msg = `SshPl.platformaInit: ${e}, state: ${JSON.stringify(this.removeSensitiveData(state))}`;
|
|
156
|
+
this.logger.error(msg);
|
|
165
157
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
158
|
+
throw new Error(msg);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
169
161
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
162
|
+
private async doStepStopExistedPlatforma(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
163
|
+
state.step = 'stopExistedPlatforma';
|
|
164
|
+
if (!isAllAlive(state.alive!, state.shouldUseMinio ?? false)) {
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
174
167
|
|
|
175
|
-
|
|
176
|
-
|
|
168
|
+
await onProgress?.('Stopping services...');
|
|
169
|
+
await this.stop();
|
|
170
|
+
}
|
|
177
171
|
|
|
178
|
-
|
|
172
|
+
private removeSensitiveData(state: PlatformaInitState): PlatformaInitState {
|
|
173
|
+
const stateCopy = { ...state };
|
|
174
|
+
stateCopy.generatedConfig = { ...stateCopy.generatedConfig, filesToCreate: { skipped: 'sanitized' } } as SshPlConfigGenerationResult;
|
|
175
|
+
return stateCopy;
|
|
176
|
+
}
|
|
179
177
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
178
|
+
private async doStepStartPlatforma(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
179
|
+
state.step = 'startPlatforma';
|
|
180
|
+
await onProgress?.('Starting Platforma on the server...');
|
|
181
|
+
await this.start(state.shouldUseMinio ?? false);
|
|
182
|
+
state.started = true;
|
|
183
|
+
this.initState = state;
|
|
183
184
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
logger: this.logger,
|
|
187
|
-
workingDir: plpath.workDir(state.remoteHome),
|
|
188
|
-
portsMode: {
|
|
189
|
-
type: 'customWithMinio',
|
|
190
|
-
ports: {
|
|
191
|
-
debug: state.ports.debug.remote,
|
|
192
|
-
grpc: state.ports.grpc.remote,
|
|
193
|
-
minio: state.ports.minioPort.remote,
|
|
194
|
-
minioConsole: state.ports.minioConsolePort.remote,
|
|
195
|
-
monitoring: state.ports.monitoring.remote,
|
|
196
|
-
|
|
197
|
-
grpcLocal: state.ports.grpc.local,
|
|
198
|
-
minioLocal: state.ports.minioPort.local,
|
|
199
|
-
},
|
|
200
|
-
},
|
|
201
|
-
licenseMode: ops.license,
|
|
202
|
-
useGlobalAccess: notEmpty(ops.useGlobalAccess),
|
|
203
|
-
plConfigPostprocessing: ops.plConfigPostprocessing,
|
|
204
|
-
});
|
|
205
|
-
state.generatedConfig = { ...config, filesToCreate: { skipped: 'it is too wordy' } };
|
|
185
|
+
await onProgress?.('Platforma has been started successfully.');
|
|
186
|
+
}
|
|
206
187
|
|
|
207
|
-
|
|
188
|
+
private async doStepSaveNewConnectionInfo(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
|
|
189
|
+
state.step = 'saveNewConnectionInfo';
|
|
190
|
+
const config = state.generatedConfig!;
|
|
191
|
+
await onProgress?.('Saving connection information...');
|
|
192
|
+
state.connectionInfo = newConnectionInfo(
|
|
193
|
+
config.plUser,
|
|
194
|
+
config.plPassword,
|
|
195
|
+
state.ports!,
|
|
196
|
+
notEmpty(ops.useGlobalAccess),
|
|
197
|
+
ops.plBinary!.version,
|
|
198
|
+
state.shouldUseMinio ?? false,
|
|
199
|
+
);
|
|
200
|
+
await this.sshClient.writeFileOnTheServer(
|
|
201
|
+
plpath.connectionInfo(state.remoteHome!),
|
|
202
|
+
stringifyConnectionInfo(state.connectionInfo),
|
|
203
|
+
);
|
|
204
|
+
await onProgress?.('Connection information saved.');
|
|
205
|
+
}
|
|
208
206
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.logger.info(`Created file ${filePath}`);
|
|
213
|
-
}
|
|
207
|
+
private async doStepConfigureSupervisord(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
208
|
+
await onProgress?.('Writing supervisord configuration...');
|
|
209
|
+
state.step = 'configureSupervisord';
|
|
214
210
|
|
|
215
|
-
|
|
216
|
-
await this.sshClient.ensureRemoteDirCreated(dir);
|
|
217
|
-
this.logger.info(`Created directory ${dir}`);
|
|
218
|
-
}
|
|
219
|
-
await onProgress?.('Folder structure created.');
|
|
211
|
+
const config = state.generatedConfig!;
|
|
220
212
|
|
|
221
|
-
|
|
222
|
-
|
|
213
|
+
let supervisorConfig: string;
|
|
214
|
+
if (state.shouldUseMinio) {
|
|
215
|
+
supervisorConfig = generateSupervisordConfigWithMinio(
|
|
223
216
|
config.minioConfig.storageDir,
|
|
224
217
|
config.minioConfig.envs,
|
|
225
|
-
await this.getFreePortForPlatformaOnServer(state.remoteHome
|
|
218
|
+
await this.getFreePortForPlatformaOnServer(state.remoteHome!, state.arch!),
|
|
226
219
|
config.workingDir,
|
|
227
220
|
config.plConfig.configPath,
|
|
228
|
-
state.binPaths
|
|
229
|
-
state.binPaths
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
const writeResult = await this.sshClient.writeFileOnTheServer(plpath.supervisorConf(state.remoteHome), supervisorConfig);
|
|
233
|
-
if (!writeResult) {
|
|
234
|
-
throw new Error(`Can not write supervisord config on the server ${plpath.workDir(state.remoteHome)}`);
|
|
235
|
-
}
|
|
236
|
-
await onProgress?.('Supervisord configuration written.');
|
|
237
|
-
|
|
238
|
-
await onProgress?.('Saving connection information...');
|
|
239
|
-
state.connectionInfo = newConnectionInfo(
|
|
240
|
-
config.plUser,
|
|
241
|
-
config.plPassword,
|
|
242
|
-
state.ports,
|
|
243
|
-
notEmpty(ops.useGlobalAccess),
|
|
244
|
-
ops.plBinary!.version,
|
|
221
|
+
state.binPaths!.minioRelPath!,
|
|
222
|
+
state.binPaths!.downloadedPl,
|
|
245
223
|
);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
224
|
+
} else {
|
|
225
|
+
supervisorConfig = generateSupervisordConfig(
|
|
226
|
+
await this.getFreePortForPlatformaOnServer(state.remoteHome!, state.arch!),
|
|
227
|
+
config.workingDir,
|
|
228
|
+
config.plConfig.configPath,
|
|
229
|
+
state.binPaths!.downloadedPl,
|
|
249
230
|
);
|
|
250
|
-
|
|
231
|
+
}
|
|
251
232
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
state.
|
|
255
|
-
|
|
233
|
+
const writeResult = await this.sshClient.writeFileOnTheServer(plpath.supervisorConf(state.remoteHome!), supervisorConfig);
|
|
234
|
+
if (!writeResult) {
|
|
235
|
+
throw new Error(`Can not write supervisord config on the server ${plpath.workDir(state.remoteHome!)}`);
|
|
236
|
+
}
|
|
237
|
+
await onProgress?.('Supervisord configuration written.');
|
|
238
|
+
}
|
|
256
239
|
|
|
257
|
-
|
|
240
|
+
private async doStepCreateFoldersAndSaveFiles(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
241
|
+
state.step = 'createFoldersAndSaveFiles';
|
|
242
|
+
const config = state.generatedConfig!;
|
|
243
|
+
await onProgress?.('Generating folder structure...');
|
|
244
|
+
for (const [filePath, content] of Object.entries(config.filesToCreate)) {
|
|
245
|
+
await this.sshClient.writeFileOnTheServer(filePath, content);
|
|
246
|
+
this.logger.info(`Created file ${filePath}`);
|
|
247
|
+
}
|
|
258
248
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
249
|
+
for (const dir of config.dirsToCreate) {
|
|
250
|
+
await this.sshClient.ensureRemoteDirCreated(dir);
|
|
251
|
+
this.logger.info(`Created directory ${dir}`);
|
|
252
|
+
}
|
|
253
|
+
await onProgress?.('Folder structure created.');
|
|
254
|
+
}
|
|
263
255
|
|
|
264
|
-
|
|
256
|
+
private async doStepGenerateNewConfig(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
|
|
257
|
+
state.step = 'generateNewConfig';
|
|
258
|
+
|
|
259
|
+
await onProgress?.('Generating new config...');
|
|
260
|
+
const config = await generateSshPlConfigs({
|
|
261
|
+
logger: this.logger,
|
|
262
|
+
workingDir: plpath.workDir(state.remoteHome!),
|
|
263
|
+
portsMode: {
|
|
264
|
+
type: 'customWithMinio',
|
|
265
|
+
ports: {
|
|
266
|
+
debug: state.ports!.debug.remote,
|
|
267
|
+
grpc: state.ports!.grpc.remote,
|
|
268
|
+
http: state.ports!.http!.remote,
|
|
269
|
+
minio: state.ports!.minioPort.remote,
|
|
270
|
+
minioConsole: state.ports!.minioConsolePort.remote,
|
|
271
|
+
monitoring: state.ports!.monitoring.remote,
|
|
272
|
+
|
|
273
|
+
httpLocal: state.ports!.http!.local,
|
|
274
|
+
grpcLocal: state.ports!.grpc.local,
|
|
275
|
+
minioLocal: state.ports!.minioPort.local,
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
licenseMode: ops.license,
|
|
279
|
+
useGlobalAccess: notEmpty(ops.useGlobalAccess),
|
|
280
|
+
plConfigPostprocessing: ops.plConfigPostprocessing,
|
|
281
|
+
useMinio: state.shouldUseMinio ?? false,
|
|
282
|
+
});
|
|
283
|
+
state.generatedConfig = { ...config };
|
|
284
|
+
await onProgress?.('New config generated');
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
private async doStepFetchPorts(state: PlatformaInitState) {
|
|
288
|
+
state.step = 'fetchPorts';
|
|
289
|
+
state.ports = await this.fetchPorts(state.remoteHome!, state.arch!);
|
|
290
|
+
|
|
291
|
+
if (!state.ports.debug.remote
|
|
292
|
+
|| !state.ports.grpc.remote
|
|
293
|
+
|| !state.ports.minioPort.remote
|
|
294
|
+
|| !state.ports.minioConsolePort.remote
|
|
295
|
+
|| !state.ports.monitoring.remote
|
|
296
|
+
|| !state.ports.http?.remote) {
|
|
297
|
+
throw new Error(`SshPl.platformaInit: remote ports are not defined`);
|
|
265
298
|
}
|
|
266
299
|
}
|
|
267
300
|
|
|
301
|
+
private async doStepDownloadBinaries(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
|
|
302
|
+
state.step = 'downloadBinaries';
|
|
303
|
+
await onProgress?.('Downloading and uploading required binaries...');
|
|
304
|
+
|
|
305
|
+
const glibcVersion = await getGlibcVersion(this.logger, this.sshClient);
|
|
306
|
+
if (glibcVersion < minRequiredGlibcVersion)
|
|
307
|
+
throw new Error(`glibc version ${glibcVersion} is too old. Version ${minRequiredGlibcVersion} or higher is required for Platforma.`);
|
|
308
|
+
|
|
309
|
+
const downloadRes = await this.downloadBinariesAndUploadToTheServer(
|
|
310
|
+
ops.localWorkdir, ops.plBinary!, state.remoteHome!, state.arch!, state.shouldUseMinio ?? false,
|
|
311
|
+
);
|
|
312
|
+
await onProgress?.('All required binaries have been downloaded and uploaded.');
|
|
313
|
+
|
|
314
|
+
state.binPaths = { ...downloadRes, history: undefined };
|
|
315
|
+
state.downloadedBinaries = downloadRes.history;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
private async doStepDetectArch(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
319
|
+
state.step = 'detectArch';
|
|
320
|
+
await onProgress?.('Detecting server architecture...');
|
|
321
|
+
state.arch = await this.getArch();
|
|
322
|
+
await onProgress?.('Server architecture detected.');
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
private async doStepDetectHome(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
|
|
326
|
+
state.step = 'detectHome';
|
|
327
|
+
await onProgress?.('Fetching user home directory...');
|
|
328
|
+
state.remoteHome = await this.getUserHomeDirectory();
|
|
329
|
+
await onProgress?.('User home directory retrieved.');
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
private async doStepReadExistedConfig(
|
|
333
|
+
state: PlatformaInitState,
|
|
334
|
+
ops: SshPlConfig,
|
|
335
|
+
onProgress: ((...args: any) => Promise<any>) | undefined,
|
|
336
|
+
): Promise<boolean> {
|
|
337
|
+
state.step = 'checkAlive';
|
|
338
|
+
await onProgress?.('Checking platform status...');
|
|
339
|
+
state.alive = await this.isAlive();
|
|
340
|
+
|
|
341
|
+
if (!state.alive?.platforma) {
|
|
342
|
+
return true;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
await onProgress?.('All required services are running.');
|
|
346
|
+
|
|
347
|
+
state.existedSettings = await this.readExistedConfig(state.remoteHome!);
|
|
348
|
+
if (!state.existedSettings) {
|
|
349
|
+
throw new Error(`SshPl.platformaInit: platforma is alive but existed settings are not found`);
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const sameGA = state.existedSettings.useGlobalAccess == ops.useGlobalAccess;
|
|
353
|
+
const samePlVersion = state.existedSettings.plVersion == ops.plBinary!.version;
|
|
354
|
+
state.needRestart = !(sameGA && samePlVersion);
|
|
355
|
+
this.logger.info(`SshPl.platformaInit: need restart? ${state.needRestart}`);
|
|
356
|
+
|
|
357
|
+
state.shouldUseMinio = state.existedSettings.minioIsUsed;
|
|
358
|
+
if (state.shouldUseMinio) {
|
|
359
|
+
this.logger.info(`SshPl.platformaInit: minio is used`);
|
|
360
|
+
} else {
|
|
361
|
+
this.logger.info(`SshPl.platformaInit: minio is not used`);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
if (!state.needRestart) {
|
|
365
|
+
await onProgress?.('Server setup completed.');
|
|
366
|
+
return false;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
await onProgress?.('Stopping services...');
|
|
370
|
+
await this.stop();
|
|
371
|
+
|
|
372
|
+
return true;
|
|
373
|
+
}
|
|
374
|
+
|
|
268
375
|
public async downloadBinariesAndUploadToTheServer(
|
|
269
376
|
localWorkdir: string,
|
|
270
377
|
plBinary: PlBinarySourceDownload,
|
|
271
378
|
remoteHome: string,
|
|
272
379
|
arch: Arch,
|
|
380
|
+
shouldUseMinio: boolean,
|
|
273
381
|
) {
|
|
274
382
|
const state: DownloadAndUntarState[] = [];
|
|
275
383
|
try {
|
|
@@ -286,16 +394,18 @@ export class SshPl {
|
|
|
286
394
|
state.push(supervisor);
|
|
287
395
|
|
|
288
396
|
const minioPath = plpath.minioBin(remoteHome, arch.arch);
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
397
|
+
if (shouldUseMinio) {
|
|
398
|
+
const minio = await this.downloadAndUntar(
|
|
399
|
+
localWorkdir, remoteHome, arch,
|
|
400
|
+
'minio', plpath.minioDirName,
|
|
401
|
+
);
|
|
402
|
+
state.push(minio);
|
|
403
|
+
await this.sshClient.chmod(minioPath, 0o750);
|
|
404
|
+
}
|
|
295
405
|
|
|
296
406
|
return {
|
|
297
407
|
history: state,
|
|
298
|
-
minioRelPath: minioPath,
|
|
408
|
+
minioRelPath: shouldUseMinio ? minioPath : undefined,
|
|
299
409
|
downloadedPl: plpath.platformaBin(remoteHome, arch.arch),
|
|
300
410
|
};
|
|
301
411
|
} catch (e: unknown) {
|
|
@@ -385,12 +495,12 @@ export class SshPl {
|
|
|
385
495
|
return false;
|
|
386
496
|
}
|
|
387
497
|
|
|
388
|
-
public async checkIsAliveWithInterval(interval: number = 1000, count = 15, shouldStart = true): Promise<void> {
|
|
498
|
+
public async checkIsAliveWithInterval(shouldUseMinio: boolean, interval: number = 1000, count = 15, shouldStart = true): Promise<void> {
|
|
389
499
|
const maxMs = count * interval;
|
|
390
500
|
|
|
391
501
|
let total = 0;
|
|
392
502
|
let alive = await this.isAlive();
|
|
393
|
-
while (shouldStart ? !alive
|
|
503
|
+
while (shouldStart ? !isAllAlive(alive, shouldUseMinio) : isAllAlive(alive, shouldUseMinio)) {
|
|
394
504
|
await sleep(interval);
|
|
395
505
|
total += interval;
|
|
396
506
|
if (total > maxMs) {
|
|
@@ -400,7 +510,7 @@ export class SshPl {
|
|
|
400
510
|
}
|
|
401
511
|
}
|
|
402
512
|
|
|
403
|
-
public async
|
|
513
|
+
public async readExistedConfig(remoteHome: string): Promise<ConnectionInfo> {
|
|
404
514
|
const connectionInfo = await this.sshClient.readFile(plpath.connectionInfo(remoteHome));
|
|
405
515
|
return parseConnectionInfo(connectionInfo);
|
|
406
516
|
}
|
|
@@ -419,6 +529,10 @@ export class SshPl {
|
|
|
419
529
|
local: await getFreePort(),
|
|
420
530
|
remote: await this.getFreePortForPlatformaOnServer(remoteHome, arch),
|
|
421
531
|
},
|
|
532
|
+
http: {
|
|
533
|
+
local: await getFreePort(),
|
|
534
|
+
remote: await this.getFreePortForPlatformaOnServer(remoteHome, arch),
|
|
535
|
+
},
|
|
422
536
|
minioPort: {
|
|
423
537
|
local: await getFreePort(),
|
|
424
538
|
remote: await this.getFreePortForPlatformaOnServer(remoteHome, arch),
|
|
@@ -506,7 +620,7 @@ const defaultSshPlConfig: Pick<
|
|
|
506
620
|
|
|
507
621
|
type BinPaths = {
|
|
508
622
|
history?: DownloadAndUntarState[];
|
|
509
|
-
minioRelPath
|
|
623
|
+
minioRelPath?: string;
|
|
510
624
|
downloadedPl: string;
|
|
511
625
|
};
|
|
512
626
|
|
|
@@ -523,14 +637,30 @@ type DownloadAndUntarState = {
|
|
|
523
637
|
untarDone?: boolean;
|
|
524
638
|
};
|
|
525
639
|
|
|
640
|
+
type PlatformaInitStep =
|
|
641
|
+
'init'
|
|
642
|
+
| 'detectArch'
|
|
643
|
+
| 'detectHome'
|
|
644
|
+
| 'checkAlive'
|
|
645
|
+
| 'stopExistedPlatforma'
|
|
646
|
+
| 'downloadBinaries'
|
|
647
|
+
| 'fetchPorts'
|
|
648
|
+
| 'generateNewConfig'
|
|
649
|
+
| 'createFoldersAndSaveFiles'
|
|
650
|
+
| 'configureSupervisord'
|
|
651
|
+
| 'saveNewConnectionInfo'
|
|
652
|
+
| 'startPlatforma';
|
|
653
|
+
|
|
526
654
|
type PlatformaInitState = {
|
|
655
|
+
step: PlatformaInitStep;
|
|
527
656
|
localWorkdir?: string;
|
|
528
657
|
plBinaryOps?: PlBinarySourceDownload;
|
|
529
658
|
arch?: Arch;
|
|
530
659
|
remoteHome?: string;
|
|
531
660
|
alive?: SupervisorStatus;
|
|
532
|
-
|
|
661
|
+
existedSettings?: ConnectionInfo;
|
|
533
662
|
needRestart?: boolean;
|
|
663
|
+
shouldUseMinio?: boolean;
|
|
534
664
|
downloadedBinaries?: DownloadAndUntarState[];
|
|
535
665
|
binPaths?: BinPaths;
|
|
536
666
|
ports?: SshPlPorts;
|
package/src/ssh/supervisord.ts
CHANGED
|
@@ -32,11 +32,22 @@ export async function supervisorStop(
|
|
|
32
32
|
export type SupervisorStatus = {
|
|
33
33
|
platforma?: boolean;
|
|
34
34
|
minio?: boolean;
|
|
35
|
-
allAlive: boolean; // true when both pl and minio are alive.
|
|
36
35
|
rawResult?: SshExecResult;
|
|
37
36
|
execError?: string;
|
|
38
37
|
};
|
|
39
38
|
|
|
39
|
+
export function isAllAlive(status: SupervisorStatus, shouldUseMinio: boolean) {
|
|
40
|
+
if (shouldUseMinio) {
|
|
41
|
+
return status.platforma && status.minio;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return status.platforma;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function isSupervisordRunning(status: SupervisorStatus) {
|
|
48
|
+
return status.execError === undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
export async function supervisorStatus(
|
|
41
52
|
logger: MiLogger,
|
|
42
53
|
sshClient: SshClient,
|
|
@@ -46,13 +57,13 @@ export async function supervisorStatus(
|
|
|
46
57
|
try {
|
|
47
58
|
result = await supervisorExec(sshClient, remoteHome, arch, 'ctl status');
|
|
48
59
|
} catch (e: unknown) {
|
|
49
|
-
return { execError: String(e)
|
|
60
|
+
return { execError: String(e) };
|
|
50
61
|
}
|
|
51
62
|
|
|
52
63
|
if (result.stderr) {
|
|
53
64
|
logger.info(`supervisord ctl status: stderr occurred: ${result.stderr}, stdout: ${result.stdout}`);
|
|
54
65
|
|
|
55
|
-
return { rawResult: result
|
|
66
|
+
return { rawResult: result };
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
const platforma = isProgramRunning(result.stdout, 'platforma');
|
|
@@ -61,13 +72,8 @@ export async function supervisorStatus(
|
|
|
61
72
|
rawResult: result,
|
|
62
73
|
platforma,
|
|
63
74
|
minio,
|
|
64
|
-
allAlive: platforma && minio,
|
|
65
75
|
};
|
|
66
76
|
|
|
67
|
-
if (status.allAlive) {
|
|
68
|
-
return status;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
77
|
if (!status.minio) {
|
|
72
78
|
logger.warn('Minio is not running on the server');
|
|
73
79
|
}
|
|
@@ -80,6 +86,39 @@ export async function supervisorStatus(
|
|
|
80
86
|
}
|
|
81
87
|
|
|
82
88
|
export function generateSupervisordConfig(
|
|
89
|
+
supervisorRemotePort: number,
|
|
90
|
+
remoteWorkDir: string,
|
|
91
|
+
platformaConfigPath: string,
|
|
92
|
+
plPath: string,
|
|
93
|
+
) {
|
|
94
|
+
const password = randomBytes(16).toString('hex');
|
|
95
|
+
const freePort = supervisorRemotePort;
|
|
96
|
+
|
|
97
|
+
return `
|
|
98
|
+
[supervisord]
|
|
99
|
+
logfile=${remoteWorkDir}/supervisord.log
|
|
100
|
+
loglevel=info
|
|
101
|
+
pidfile=${remoteWorkDir}/supervisord.pid
|
|
102
|
+
|
|
103
|
+
[inet_http_server]
|
|
104
|
+
port=127.0.0.1:${freePort}
|
|
105
|
+
username=default-user
|
|
106
|
+
password=${password}
|
|
107
|
+
|
|
108
|
+
[supervisorctl]
|
|
109
|
+
serverurl=http://127.0.0.1:${freePort}
|
|
110
|
+
username=default-user
|
|
111
|
+
password=${password}
|
|
112
|
+
|
|
113
|
+
[program:platforma]
|
|
114
|
+
autostart=true
|
|
115
|
+
command=${plPath} --config ${platformaConfigPath}
|
|
116
|
+
directory=${remoteWorkDir}
|
|
117
|
+
autorestart=true
|
|
118
|
+
`;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function generateSupervisordConfigWithMinio(
|
|
83
122
|
minioStorageDir: string,
|
|
84
123
|
minioEnvs: Record<string, string>,
|
|
85
124
|
supervisorRemotePort: number,
|