@milaboratories/pl-deployments 2.15.7 → 2.15.9

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.
Files changed (106) hide show
  1. package/README.md +18 -5
  2. package/dist/common/os_and_arch.cjs +19 -19
  3. package/dist/common/os_and_arch.cjs.map +1 -1
  4. package/dist/common/os_and_arch.js +19 -19
  5. package/dist/common/os_and_arch.js.map +1 -1
  6. package/dist/common/pl_binary.cjs +9 -9
  7. package/dist/common/pl_binary.cjs.map +1 -1
  8. package/dist/common/pl_binary.d.ts +6 -6
  9. package/dist/common/pl_binary.d.ts.map +1 -1
  10. package/dist/common/pl_binary.js +9 -9
  11. package/dist/common/pl_binary.js.map +1 -1
  12. package/dist/common/pl_binary_download.cjs +16 -16
  13. package/dist/common/pl_binary_download.cjs.map +1 -1
  14. package/dist/common/pl_binary_download.d.ts +6 -6
  15. package/dist/common/pl_binary_download.d.ts.map +1 -1
  16. package/dist/common/pl_binary_download.js +16 -16
  17. package/dist/common/pl_binary_download.js.map +1 -1
  18. package/dist/common/pl_version.cjs +1 -1
  19. package/dist/common/pl_version.cjs.map +1 -1
  20. package/dist/common/pl_version.js +1 -1
  21. package/dist/common/pl_version.js.map +1 -1
  22. package/dist/index.d.ts +5 -5
  23. package/dist/local/options.d.ts +4 -4
  24. package/dist/local/pid.cjs +1 -1
  25. package/dist/local/pid.cjs.map +1 -1
  26. package/dist/local/pid.js +1 -1
  27. package/dist/local/pid.js.map +1 -1
  28. package/dist/local/pl.cjs +26 -26
  29. package/dist/local/pl.cjs.map +1 -1
  30. package/dist/local/pl.d.ts +8 -8
  31. package/dist/local/pl.d.ts.map +1 -1
  32. package/dist/local/pl.js +26 -26
  33. package/dist/local/pl.js.map +1 -1
  34. package/dist/local/process.cjs +16 -16
  35. package/dist/local/process.cjs.map +1 -1
  36. package/dist/local/process.d.ts +2 -2
  37. package/dist/local/process.js +16 -16
  38. package/dist/local/process.js.map +1 -1
  39. package/dist/local/trace.cjs.map +1 -1
  40. package/dist/local/trace.d.ts +1 -1
  41. package/dist/local/trace.js.map +1 -1
  42. package/dist/package.json.cjs +2 -1
  43. package/dist/package.json.cjs.map +1 -1
  44. package/dist/package.json.js +2 -1
  45. package/dist/package.json.js.map +1 -1
  46. package/dist/ssh/__tests__/common-utils.d.ts +2 -2
  47. package/dist/ssh/__tests__/common-utils.d.ts.map +1 -1
  48. package/dist/ssh/connection_info.cjs +13 -7
  49. package/dist/ssh/connection_info.cjs.map +1 -1
  50. package/dist/ssh/connection_info.d.ts +1 -1
  51. package/dist/ssh/connection_info.d.ts.map +1 -1
  52. package/dist/ssh/connection_info.js +13 -7
  53. package/dist/ssh/connection_info.js.map +1 -1
  54. package/dist/ssh/pl.cjs +79 -76
  55. package/dist/ssh/pl.cjs.map +1 -1
  56. package/dist/ssh/pl.d.ts +18 -18
  57. package/dist/ssh/pl.d.ts.map +1 -1
  58. package/dist/ssh/pl.js +79 -76
  59. package/dist/ssh/pl.js.map +1 -1
  60. package/dist/ssh/pl_paths.cjs +13 -13
  61. package/dist/ssh/pl_paths.cjs.map +1 -1
  62. package/dist/ssh/pl_paths.d.ts.map +1 -1
  63. package/dist/ssh/pl_paths.js +13 -13
  64. package/dist/ssh/pl_paths.js.map +1 -1
  65. package/dist/ssh/ssh.cjs +43 -40
  66. package/dist/ssh/ssh.cjs.map +1 -1
  67. package/dist/ssh/ssh.d.ts +9 -9
  68. package/dist/ssh/ssh.d.ts.map +1 -1
  69. package/dist/ssh/ssh.js +43 -40
  70. package/dist/ssh/ssh.js.map +1 -1
  71. package/dist/ssh/ssh_errors.cjs +7 -5
  72. package/dist/ssh/ssh_errors.cjs.map +1 -1
  73. package/dist/ssh/ssh_errors.d.ts.map +1 -1
  74. package/dist/ssh/ssh_errors.js +7 -5
  75. package/dist/ssh/ssh_errors.js.map +1 -1
  76. package/dist/ssh/supervisord.cjs +15 -13
  77. package/dist/ssh/supervisord.cjs.map +1 -1
  78. package/dist/ssh/supervisord.d.ts +2 -2
  79. package/dist/ssh/supervisord.d.ts.map +1 -1
  80. package/dist/ssh/supervisord.js +15 -13
  81. package/dist/ssh/supervisord.js.map +1 -1
  82. package/package.json +38 -37
  83. package/src/common/os_and_arch.ts +19 -19
  84. package/src/common/pl_binary.ts +30 -27
  85. package/src/common/pl_binary_download.ts +80 -59
  86. package/src/common/pl_version.ts +2 -2
  87. package/src/index.ts +5 -5
  88. package/src/local/config.test.yaml +19 -19
  89. package/src/local/options.ts +4 -4
  90. package/src/local/pid.ts +4 -4
  91. package/src/local/pl.test.ts +245 -253
  92. package/src/local/pl.ts +45 -50
  93. package/src/local/process.ts +21 -21
  94. package/src/local/trace.ts +1 -1
  95. package/src/ssh/__tests__/common-utils.ts +21 -19
  96. package/src/ssh/__tests__/pl-docker.test.ts +68 -59
  97. package/src/ssh/__tests__/ssh-docker.test.ts +152 -90
  98. package/src/ssh/__tests__/ssh-upload.test.ts +42 -31
  99. package/src/ssh/connection_info.ts +33 -27
  100. package/src/ssh/pl.test.ts +15 -13
  101. package/src/ssh/pl.ts +228 -143
  102. package/src/ssh/pl_paths.ts +22 -18
  103. package/src/ssh/ssh.ts +151 -74
  104. package/src/ssh/ssh_errors.test.ts +39 -39
  105. package/src/ssh/ssh_errors.ts +8 -6
  106. package/src/ssh/supervisord.ts +28 -28
package/src/ssh/pl.ts CHANGED
@@ -1,34 +1,46 @@
1
- import type * as ssh from 'ssh2';
2
- import { SshClient } from './ssh';
3
- import type { MiLogger } from '@milaboratories/ts-helpers';
4
- import { sleep, notEmpty } from '@milaboratories/ts-helpers';
5
- import type { DownloadBinaryResult } from '../common/pl_binary_download';
6
- import { downloadBinaryNoExtract } from '../common/pl_binary_download';
7
- import upath from 'upath';
8
- import * as plpath from './pl_paths';
9
- import { getDefaultPlVersion } from '../common/pl_version';
10
- import type { ProxySettings } from '@milaboratories/pl-http';
11
- import { defaultHttpDispatcher } from '@milaboratories/pl-http';
12
- import type { Dispatcher } from 'undici';
13
-
14
- import net from 'node:net';
15
- import type { PlConfig, PlLicenseMode, SshPlConfigGenerationResult } from '@milaboratories/pl-config';
16
- import { getFreePort, generateSshPlConfigs } from '@milaboratories/pl-config';
17
- import type { SupervisorStatus } from './supervisord';
18
- import { supervisorStatus, supervisorStop as supervisorCtlShutdown, generateSupervisordConfigWithMinio, supervisorCtlStart, isSupervisordRunning, generateSupervisordConfig, isAllAlive } from './supervisord';
19
- import type { ConnectionInfo, SshPlPorts } from './connection_info';
20
- import { newConnectionInfo, parseConnectionInfo, stringifyConnectionInfo } from './connection_info';
21
- import type { PlBinarySourceDownload } from '../common/pl_binary';
1
+ import type * as ssh from "ssh2";
2
+ import { SshClient } from "./ssh";
3
+ import type { MiLogger } from "@milaboratories/ts-helpers";
4
+ import { sleep, notEmpty } from "@milaboratories/ts-helpers";
5
+ import type { DownloadBinaryResult } from "../common/pl_binary_download";
6
+ import { downloadBinaryNoExtract } from "../common/pl_binary_download";
7
+ import upath from "upath";
8
+ import * as plpath from "./pl_paths";
9
+ import { getDefaultPlVersion } from "../common/pl_version";
10
+ import type { ProxySettings } from "@milaboratories/pl-http";
11
+ import { defaultHttpDispatcher } from "@milaboratories/pl-http";
12
+ import type { Dispatcher } from "undici";
13
+
14
+ import net from "node:net";
15
+ import type {
16
+ PlConfig,
17
+ PlLicenseMode,
18
+ SshPlConfigGenerationResult,
19
+ } from "@milaboratories/pl-config";
20
+ import { getFreePort, generateSshPlConfigs } from "@milaboratories/pl-config";
21
+ import type { SupervisorStatus } from "./supervisord";
22
+ import {
23
+ supervisorStatus,
24
+ supervisorStop as supervisorCtlShutdown,
25
+ generateSupervisordConfigWithMinio,
26
+ supervisorCtlStart,
27
+ isSupervisordRunning,
28
+ generateSupervisordConfig,
29
+ isAllAlive,
30
+ } from "./supervisord";
31
+ import type { ConnectionInfo, SshPlPorts } from "./connection_info";
32
+ import { newConnectionInfo, parseConnectionInfo, stringifyConnectionInfo } from "./connection_info";
33
+ import type { PlBinarySourceDownload } from "../common/pl_binary";
22
34
 
23
35
  const minRequiredGlibcVersion = 2.28;
24
36
 
25
37
  export class SshPl {
26
- private initState: PlatformaInitState = { step: 'init' };
38
+ private initState: PlatformaInitState = { step: "init" };
27
39
  constructor(
28
40
  public readonly logger: MiLogger,
29
41
  public readonly sshClient: SshClient,
30
42
  private readonly username: string,
31
- ) { }
43
+ ) {}
32
44
 
33
45
  public info() {
34
46
  return {
@@ -59,7 +71,7 @@ export class SshPl {
59
71
  }
60
72
 
61
73
  /** Starts all the services on the server.
62
- * Idempotent semantic: we could call it several times. */
74
+ * Idempotent semantic: we could call it several times. */
63
75
  public async start(shouldUseMinio: boolean) {
64
76
  const arch = await this.getArch();
65
77
  const remoteHome = await this.getUserHomeDirectory();
@@ -74,7 +86,7 @@ export class SshPl {
74
86
  } catch (e: unknown) {
75
87
  let msg = `SshPl.start: ${e}`;
76
88
 
77
- let logs = '';
89
+ let logs = "";
78
90
  try {
79
91
  logs = await this.sshClient.readFile(plpath.platformaCliLogs(remoteHome));
80
92
  msg += `, platforma cli logs: ${logs}`;
@@ -88,7 +100,7 @@ export class SshPl {
88
100
  }
89
101
 
90
102
  /** Stops all the services on the server.
91
- * Idempotent semantic: we could call it several times. */
103
+ * Idempotent semantic: we could call it several times. */
92
104
  public async stop() {
93
105
  const arch = await this.getArch();
94
106
  const remoteHome = await this.getUserHomeDirectory();
@@ -122,7 +134,9 @@ export class SshPl {
122
134
  this.logger.info(`pl.reset: Stop Platforma on the server`);
123
135
  await this.stop();
124
136
 
125
- this.logger.info(`pl.reset: Deleting Platforma workDir ${plpath.workDir(remoteHome)} on the server`);
137
+ this.logger.info(
138
+ `pl.reset: Deleting Platforma workDir ${plpath.workDir(remoteHome)} on the server`,
139
+ );
126
140
  await this.sshClient.deleteFolder(plpath.workDir(remoteHome));
127
141
  }
128
142
 
@@ -130,7 +144,7 @@ export class SshPl {
130
144
  * generates all the configs, creates necessary dirs,
131
145
  * and finally starts all the services. */
132
146
  public async platformaInit(options: SshPlConfig): Promise<ConnectionInfo> {
133
- const state: PlatformaInitState = { localWorkdir: options.localWorkdir, step: 'init' };
147
+ const state: PlatformaInitState = { localWorkdir: options.localWorkdir, step: "init" };
134
148
 
135
149
  const { onProgress } = options;
136
150
 
@@ -147,13 +161,13 @@ export class SshPl {
147
161
 
148
162
  const needRestartPlatforma = await this.doStepReadExistedConfig(state, ops, onProgress);
149
163
  if (!needRestartPlatforma) {
150
- await onProgress?.('Platforma is already running. Skipping initialization.');
164
+ await onProgress?.("Platforma is already running. Skipping initialization.");
151
165
  return state.existedSettings!;
152
166
  }
153
167
  await this.doStepStopExistedPlatforma(state, onProgress);
154
168
  await this.doStepCheckDbLock(state, onProgress);
155
169
 
156
- await onProgress?.('Installation platforma...');
170
+ await onProgress?.("Installation platforma...");
157
171
 
158
172
  await this.doStepDownloadBinaries(state, onProgress, ops);
159
173
  await this.doStepFetchPorts(state);
@@ -172,36 +186,49 @@ export class SshPl {
172
186
  }
173
187
  }
174
188
 
175
- private async doStepStopExistedPlatforma(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
176
- state.step = 'stopExistedPlatforma';
189
+ private async doStepStopExistedPlatforma(
190
+ state: PlatformaInitState,
191
+ onProgress: ((...args: any) => Promise<any>) | undefined,
192
+ ) {
193
+ state.step = "stopExistedPlatforma";
177
194
  if (!isAllAlive(state.alive!, state.shouldUseMinio ?? false)) {
178
195
  return;
179
196
  }
180
197
 
181
- await onProgress?.('Stopping services...');
198
+ await onProgress?.("Stopping services...");
182
199
  await this.stop();
183
200
  }
184
201
 
185
202
  private removeSensitiveData(state: PlatformaInitState): PlatformaInitState {
186
203
  const stateCopy = { ...state };
187
- stateCopy.generatedConfig = { ...stateCopy.generatedConfig, filesToCreate: { skipped: 'sanitized' } } as SshPlConfigGenerationResult;
204
+ stateCopy.generatedConfig = {
205
+ ...stateCopy.generatedConfig,
206
+ filesToCreate: { skipped: "sanitized" },
207
+ } as SshPlConfigGenerationResult;
188
208
  return stateCopy;
189
209
  }
190
210
 
191
- private async doStepStartPlatforma(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
192
- state.step = 'startPlatforma';
193
- await onProgress?.('Starting Platforma on the server...');
211
+ private async doStepStartPlatforma(
212
+ state: PlatformaInitState,
213
+ onProgress: ((...args: any) => Promise<any>) | undefined,
214
+ ) {
215
+ state.step = "startPlatforma";
216
+ await onProgress?.("Starting Platforma on the server...");
194
217
  await this.start(state.shouldUseMinio ?? false);
195
218
  state.started = true;
196
219
  this.initState = state;
197
220
 
198
- await onProgress?.('Platforma has been started successfully.');
221
+ await onProgress?.("Platforma has been started successfully.");
199
222
  }
200
223
 
201
- private async doStepSaveNewConnectionInfo(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
202
- state.step = 'saveNewConnectionInfo';
224
+ private async doStepSaveNewConnectionInfo(
225
+ state: PlatformaInitState,
226
+ onProgress: ((...args: any) => Promise<any>) | undefined,
227
+ ops: SshPlConfig,
228
+ ) {
229
+ state.step = "saveNewConnectionInfo";
203
230
  const config = state.generatedConfig!;
204
- await onProgress?.('Saving connection information...');
231
+ await onProgress?.("Saving connection information...");
205
232
  state.connectionInfo = newConnectionInfo(
206
233
  config.plUser,
207
234
  config.plPassword,
@@ -214,7 +241,7 @@ export class SshPl {
214
241
  plpath.connectionInfo(state.remoteHome!),
215
242
  stringifyConnectionInfo(state.connectionInfo),
216
243
  );
217
- await onProgress?.('Connection information saved.');
244
+ await onProgress?.("Connection information saved.");
218
245
  }
219
246
 
220
247
  private async doStepCheckDbLock(
@@ -232,14 +259,14 @@ export class SshPl {
232
259
  }
233
260
  };
234
261
 
235
- state.step = 'checkDbLock';
236
- await onProgress?.('Checking for DB lock...');
262
+ state.step = "checkDbLock";
263
+ await onProgress?.("Checking for DB lock...");
237
264
 
238
265
  const lockFilePath = plpath.platformaDbLock(state.remoteHome!);
239
266
  const lockFileExists = await this.sshClient.checkFileExists(lockFilePath);
240
267
 
241
268
  if (!lockFileExists) {
242
- await onProgress?.('No DB lock found. Proceeding...');
269
+ await onProgress?.("No DB lock found. Proceeding...");
243
270
  return;
244
271
  }
245
272
 
@@ -247,7 +274,9 @@ export class SshPl {
247
274
  const lockProcessInfo = await this.findLockHolder(lockFilePath);
248
275
 
249
276
  if (!lockProcessInfo) {
250
- this.logger.warn('Lock file exists but no process is holding it. Removing stale lock file...');
277
+ this.logger.warn(
278
+ "Lock file exists but no process is holding it. Removing stale lock file...",
279
+ );
251
280
  await removeLockFile(lockFilePath);
252
281
  return;
253
282
  }
@@ -257,17 +286,19 @@ export class SshPl {
257
286
  );
258
287
 
259
288
  if (lockProcessInfo.user !== this.username) {
260
- const msg
261
- = `DB lock is held by process ${lockProcessInfo.pid} `
262
- + `owned by user '${lockProcessInfo.user}', but current user is '${this.username}'. `
263
- + 'Cannot kill process owned by different user.';
289
+ const msg =
290
+ `DB lock is held by process ${lockProcessInfo.pid} ` +
291
+ `owned by user '${lockProcessInfo.user}', but current user is '${this.username}'. ` +
292
+ "Cannot kill process owned by different user.";
264
293
  this.logger.error(msg);
265
294
  throw new Error(msg);
266
295
  }
267
296
 
268
- this.logger.info(`Process ${lockProcessInfo.pid} belongs to current user ${this.username}. Killing it...`);
297
+ this.logger.info(
298
+ `Process ${lockProcessInfo.pid} belongs to current user ${this.username}. Killing it...`,
299
+ );
269
300
  await this.killRemoteProcess(lockProcessInfo.pid);
270
- this.logger.info('Process holding DB lock has been terminated.');
301
+ this.logger.info("Process holding DB lock has been terminated.");
271
302
 
272
303
  // Verify lock file is gone or can be removed
273
304
  const lockStillExists = await this.sshClient.checkFileExists(lockFilePath);
@@ -276,9 +307,12 @@ export class SshPl {
276
307
  }
277
308
  }
278
309
 
279
- private async doStepConfigureSupervisord(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
280
- await onProgress?.('Writing supervisord configuration...');
281
- state.step = 'configureSupervisord';
310
+ private async doStepConfigureSupervisord(
311
+ state: PlatformaInitState,
312
+ onProgress: ((...args: any) => Promise<any>) | undefined,
313
+ ) {
314
+ await onProgress?.("Writing supervisord configuration...");
315
+ state.step = "configureSupervisord";
282
316
 
283
317
  const config = state.generatedConfig!;
284
318
 
@@ -302,17 +336,25 @@ export class SshPl {
302
336
  );
303
337
  }
304
338
 
305
- const writeResult = await this.sshClient.writeFileOnTheServer(plpath.supervisorConf(state.remoteHome!), supervisorConfig);
339
+ const writeResult = await this.sshClient.writeFileOnTheServer(
340
+ plpath.supervisorConf(state.remoteHome!),
341
+ supervisorConfig,
342
+ );
306
343
  if (!writeResult) {
307
- throw new Error(`Can not write supervisord config on the server ${plpath.workDir(state.remoteHome!)}`);
344
+ throw new Error(
345
+ `Can not write supervisord config on the server ${plpath.workDir(state.remoteHome!)}`,
346
+ );
308
347
  }
309
- await onProgress?.('Supervisord configuration written.');
348
+ await onProgress?.("Supervisord configuration written.");
310
349
  }
311
350
 
312
- private async doStepCreateFoldersAndSaveFiles(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
313
- state.step = 'createFoldersAndSaveFiles';
351
+ private async doStepCreateFoldersAndSaveFiles(
352
+ state: PlatformaInitState,
353
+ onProgress: ((...args: any) => Promise<any>) | undefined,
354
+ ) {
355
+ state.step = "createFoldersAndSaveFiles";
314
356
  const config = state.generatedConfig!;
315
- await onProgress?.('Generating folder structure...');
357
+ await onProgress?.("Generating folder structure...");
316
358
  for (const [filePath, content] of Object.entries(config.filesToCreate)) {
317
359
  await this.sshClient.writeFileOnTheServer(filePath, content);
318
360
  this.logger.info(`Created file ${filePath}`);
@@ -322,18 +364,22 @@ export class SshPl {
322
364
  await this.sshClient.ensureRemoteDirCreated(dir);
323
365
  this.logger.info(`Created directory ${dir}`);
324
366
  }
325
- await onProgress?.('Folder structure created.');
367
+ await onProgress?.("Folder structure created.");
326
368
  }
327
369
 
328
- private async doStepGenerateNewConfig(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
329
- state.step = 'generateNewConfig';
370
+ private async doStepGenerateNewConfig(
371
+ state: PlatformaInitState,
372
+ onProgress: ((...args: any) => Promise<any>) | undefined,
373
+ ops: SshPlConfig,
374
+ ) {
375
+ state.step = "generateNewConfig";
330
376
 
331
- await onProgress?.('Generating new config...');
377
+ await onProgress?.("Generating new config...");
332
378
  const config = await generateSshPlConfigs({
333
379
  logger: this.logger,
334
380
  workingDir: plpath.workDir(state.remoteHome!),
335
381
  portsMode: {
336
- type: 'customWithMinio',
382
+ type: "customWithMinio",
337
383
  ports: {
338
384
  debug: state.ports!.debug.remote,
339
385
  grpc: state.ports!.grpc.remote,
@@ -353,53 +399,71 @@ export class SshPl {
353
399
  useMinio: state.shouldUseMinio ?? false,
354
400
  });
355
401
  state.generatedConfig = { ...config };
356
- await onProgress?.('New config generated');
402
+ await onProgress?.("New config generated");
357
403
  }
358
404
 
359
405
  private async doStepFetchPorts(state: PlatformaInitState) {
360
- state.step = 'fetchPorts';
406
+ state.step = "fetchPorts";
361
407
  state.ports = await this.fetchPorts(state.remoteHome!, state.arch!);
362
408
 
363
- if (!state.ports.debug.remote
364
- || !state.ports.grpc.remote
365
- || !state.ports.minioPort.remote
366
- || !state.ports.minioConsolePort.remote
367
- || !state.ports.monitoring.remote
368
- || !state.ports.http?.remote) {
409
+ if (
410
+ !state.ports.debug.remote ||
411
+ !state.ports.grpc.remote ||
412
+ !state.ports.minioPort.remote ||
413
+ !state.ports.minioConsolePort.remote ||
414
+ !state.ports.monitoring.remote ||
415
+ !state.ports.http?.remote
416
+ ) {
369
417
  throw new Error(`SshPl.platformaInit: remote ports are not defined`);
370
418
  }
371
419
  }
372
420
 
373
- private async doStepDownloadBinaries(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined, ops: SshPlConfig) {
374
- state.step = 'downloadBinaries';
375
- await onProgress?.('Downloading and uploading required binaries...');
421
+ private async doStepDownloadBinaries(
422
+ state: PlatformaInitState,
423
+ onProgress: ((...args: any) => Promise<any>) | undefined,
424
+ ops: SshPlConfig,
425
+ ) {
426
+ state.step = "downloadBinaries";
427
+ await onProgress?.("Downloading and uploading required binaries...");
376
428
 
377
429
  const glibcVersion = await getGlibcVersion(this.logger, this.sshClient);
378
430
  if (glibcVersion < minRequiredGlibcVersion)
379
- throw new Error(`glibc version ${glibcVersion} is too old. Version ${minRequiredGlibcVersion} or higher is required for Platforma.`);
431
+ throw new Error(
432
+ `glibc version ${glibcVersion} is too old. Version ${minRequiredGlibcVersion} or higher is required for Platforma.`,
433
+ );
380
434
 
381
435
  const downloadRes = await this.downloadBinariesAndUploadToTheServer(
382
- ops.localWorkdir, ops.plBinary!, state.remoteHome!, state.arch!, state.shouldUseMinio ?? false,
436
+ ops.localWorkdir,
437
+ ops.plBinary!,
438
+ state.remoteHome!,
439
+ state.arch!,
440
+ state.shouldUseMinio ?? false,
383
441
  ops.proxy,
384
442
  );
385
- await onProgress?.('All required binaries have been downloaded and uploaded.');
443
+ await onProgress?.("All required binaries have been downloaded and uploaded.");
386
444
 
387
445
  state.binPaths = { ...downloadRes, history: undefined };
388
446
  state.downloadedBinaries = downloadRes.history;
389
447
  }
390
448
 
391
- private async doStepDetectArch(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
392
- state.step = 'detectArch';
393
- await onProgress?.('Detecting server architecture...');
449
+ private async doStepDetectArch(
450
+ state: PlatformaInitState,
451
+ onProgress: ((...args: any) => Promise<any>) | undefined,
452
+ ) {
453
+ state.step = "detectArch";
454
+ await onProgress?.("Detecting server architecture...");
394
455
  state.arch = await this.getArch();
395
- await onProgress?.('Server architecture detected.');
456
+ await onProgress?.("Server architecture detected.");
396
457
  }
397
458
 
398
- private async doStepDetectHome(state: PlatformaInitState, onProgress: ((...args: any) => Promise<any>) | undefined) {
399
- state.step = 'detectHome';
400
- await onProgress?.('Fetching user home directory...');
459
+ private async doStepDetectHome(
460
+ state: PlatformaInitState,
461
+ onProgress: ((...args: any) => Promise<any>) | undefined,
462
+ ) {
463
+ state.step = "detectHome";
464
+ await onProgress?.("Fetching user home directory...");
401
465
  state.remoteHome = await this.getUserHomeDirectory();
402
- await onProgress?.('User home directory retrieved.');
466
+ await onProgress?.("User home directory retrieved.");
403
467
  }
404
468
 
405
469
  private async doStepReadExistedConfig(
@@ -407,15 +471,15 @@ export class SshPl {
407
471
  ops: SshPlConfig,
408
472
  onProgress: ((...args: any) => Promise<any>) | undefined,
409
473
  ): Promise<boolean> {
410
- state.step = 'checkAlive';
411
- await onProgress?.('Checking platform status...');
474
+ state.step = "checkAlive";
475
+ await onProgress?.("Checking platform status...");
412
476
  state.alive = await this.isAlive();
413
477
 
414
478
  if (!state.alive?.platforma) {
415
479
  return true;
416
480
  }
417
481
 
418
- await onProgress?.('All required services are running.');
482
+ await onProgress?.("All required services are running.");
419
483
 
420
484
  state.existedSettings = await this.readExistedConfig(state.remoteHome!);
421
485
  if (!state.existedSettings) {
@@ -435,11 +499,11 @@ export class SshPl {
435
499
  }
436
500
 
437
501
  if (!state.needRestart) {
438
- await onProgress?.('Server setup completed.');
502
+ await onProgress?.("Server setup completed.");
439
503
  return false;
440
504
  }
441
505
 
442
- await onProgress?.('Stopping services...');
506
+ await onProgress?.("Stopping services...");
443
507
  await this.stop();
444
508
 
445
509
  return true;
@@ -457,15 +521,21 @@ export class SshPl {
457
521
  const dispatcher = defaultHttpDispatcher(proxy);
458
522
  try {
459
523
  const pl = await this.downloadAndUntar(
460
- localWorkdir, remoteHome, arch,
461
- 'pl', `pl-${plBinary.version}`,
524
+ localWorkdir,
525
+ remoteHome,
526
+ arch,
527
+ "pl",
528
+ `pl-${plBinary.version}`,
462
529
  dispatcher,
463
530
  );
464
531
  state.push(pl);
465
532
 
466
533
  const supervisor = await this.downloadAndUntar(
467
- localWorkdir, remoteHome, arch,
468
- 'supervisord', plpath.supervisordDirName,
534
+ localWorkdir,
535
+ remoteHome,
536
+ arch,
537
+ "supervisord",
538
+ plpath.supervisordDirName,
469
539
  dispatcher,
470
540
  );
471
541
  state.push(supervisor);
@@ -473,8 +543,11 @@ export class SshPl {
473
543
  const minioPath = plpath.minioBin(remoteHome, arch.arch);
474
544
  if (shouldUseMinio) {
475
545
  const minio = await this.downloadAndUntar(
476
- localWorkdir, remoteHome, arch,
477
- 'minio', plpath.minioDirName,
546
+ localWorkdir,
547
+ remoteHome,
548
+ arch,
549
+ "minio",
550
+ plpath.minioDirName,
478
551
  dispatcher,
479
552
  );
480
553
  state.push(minio);
@@ -506,7 +579,7 @@ export class SshPl {
506
579
  // Example:
507
580
  // COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
508
581
  // platforma 11628 rfiskov 10u REG 1,16 0 66670038 ./LOCK
509
- const lines = output.split('\n');
582
+ const lines = output.split("\n");
510
583
  if (lines.length <= 1) {
511
584
  return null;
512
585
  }
@@ -593,11 +666,11 @@ export class SshPl {
593
666
  }
594
667
 
595
668
  /** We have to extract pl in the remote server,
596
- * because Windows doesn't support symlinks
597
- * that are found in Linux pl binaries tgz archive.
598
- * For this reason, we extract all to the remote server.
599
- * It requires `tar` to be installed on the server
600
- * (it's not installed for Rocky Linux for example). */
669
+ * because Windows doesn't support symlinks
670
+ * that are found in Linux pl binaries tgz archive.
671
+ * For this reason, we extract all to the remote server.
672
+ * It requires `tar` to be installed on the server
673
+ * (it's not installed for Rocky Linux for example). */
601
674
  public async downloadAndUntar(
602
675
  localWorkdir: string,
603
676
  remoteHome: string,
@@ -636,16 +709,18 @@ export class SshPl {
636
709
 
637
710
  state.localArchivePath = upath.resolve(state.downloadResult.archivePath);
638
711
  state.remoteDir = upath.join(state.binBasePath, state.downloadResult.baseName);
639
- state.remoteArchivePath = state.remoteDir + '.tgz';
712
+ state.remoteArchivePath = state.remoteDir + ".tgz";
640
713
 
641
714
  await this.sshClient.ensureRemoteDirCreated(state.remoteDir);
642
715
  await this.sshClient.uploadFile(state.localArchivePath, state.remoteArchivePath);
643
716
  state.uploadDone = true;
644
717
 
645
718
  try {
646
- await this.sshClient.exec('hash tar');
647
- } catch (_) {
648
- throw new Error(`tar is not installed on the server. Please install it before running Platforma.`);
719
+ await this.sshClient.exec("hash tar");
720
+ } catch {
721
+ throw new Error(
722
+ `tar is not installed on the server. Please install it before running Platforma.`,
723
+ );
649
724
  }
650
725
 
651
726
  // TODO: Create a proper archive to avoid xattr warnings
@@ -654,7 +729,9 @@ export class SshPl {
654
729
  );
655
730
 
656
731
  if (untarResult.stderr)
657
- throw new Error(`downloadAndUntar: untar: stderr occurred: ${untarResult.stderr}, stdout: ${untarResult.stdout}`);
732
+ throw new Error(
733
+ `downloadAndUntar: untar: stderr occurred: ${untarResult.stderr}, stdout: ${untarResult.stdout}`,
734
+ );
658
735
 
659
736
  state.untarDone = true;
660
737
 
@@ -666,16 +743,23 @@ export class SshPl {
666
743
  const checkPathMinio = plpath.minioDir(remoteHome, arch.arch);
667
744
  const checkPathPlatforma = plpath.platformaBin(remoteHome, arch.arch);
668
745
 
669
- if (!await this.sshClient.checkFileExists(checkPathPlatforma)
670
- || !await this.sshClient.checkFileExists(checkPathMinio)
671
- || !await this.sshClient.checkFileExists(checkPathSupervisor)) {
746
+ if (
747
+ !(await this.sshClient.checkFileExists(checkPathPlatforma)) ||
748
+ !(await this.sshClient.checkFileExists(checkPathMinio)) ||
749
+ !(await this.sshClient.checkFileExists(checkPathSupervisor))
750
+ ) {
672
751
  return true;
673
752
  }
674
753
 
675
754
  return false;
676
755
  }
677
756
 
678
- public async checkIsAliveWithInterval(shouldUseMinio: boolean, interval: number = 1000, count = 15, shouldStart = true): Promise<void> {
757
+ public async checkIsAliveWithInterval(
758
+ shouldUseMinio: boolean,
759
+ interval: number = 1000,
760
+ count = 15,
761
+ shouldStart = true,
762
+ ): Promise<void> {
679
763
  const maxMs = count * interval;
680
764
 
681
765
  let total = 0;
@@ -684,7 +768,9 @@ export class SshPl {
684
768
  await sleep(interval);
685
769
  total += interval;
686
770
  if (total > maxMs) {
687
- throw new Error(`isAliveWithInterval: The process did not ${shouldStart ? 'started' : 'stopped'} after ${maxMs} ms. Live status: ${JSON.stringify(alive)}`);
771
+ throw new Error(
772
+ `isAliveWithInterval: The process did not ${shouldStart ? "started" : "stopped"} after ${maxMs} ms. Live status: ${JSON.stringify(alive)}`,
773
+ );
688
774
  }
689
775
  alive = await this.isAlive();
690
776
  }
@@ -741,18 +827,19 @@ export class SshPl {
741
827
 
742
828
  const { stdout, stderr } = await this.sshClient.exec(`${freePortBin}`);
743
829
  if (stderr) {
744
- throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${stderr}, stdout: ${stdout}`);
830
+ throw new Error(
831
+ `getFreePortForPlatformaOnServer: stderr is not empty: ${stderr}, stdout: ${stdout}`,
832
+ );
745
833
  }
746
834
 
747
835
  return +stdout;
748
836
  }
749
837
 
750
838
  public async getArch(): Promise<Arch> {
751
- const { stdout, stderr } = await this.sshClient.exec('uname -s && uname -m');
752
- if (stderr)
753
- throw new Error(`getArch: stderr is not empty: ${stderr}, stdout: ${stdout}`);
839
+ const { stdout, stderr } = await this.sshClient.exec("uname -s && uname -m");
840
+ if (stderr) throw new Error(`getArch: stderr is not empty: ${stderr}, stdout: ${stdout}`);
754
841
 
755
- const arr = stdout.split('\n');
842
+ const arr = stdout.split("\n");
756
843
 
757
844
  return {
758
845
  platform: arr[0],
@@ -761,11 +848,13 @@ export class SshPl {
761
848
  }
762
849
 
763
850
  public async getUserHomeDirectory() {
764
- const { stdout, stderr } = await this.sshClient.exec('echo $HOME');
851
+ const { stdout, stderr } = await this.sshClient.exec("echo $HOME");
765
852
 
766
853
  if (stderr) {
767
854
  const home = `/home/${this.username}`;
768
- console.warn(`getUserHomeDirectory: stderr is not empty: ${stderr}, stdout: ${stdout}, will get a default home: ${home}`);
855
+ console.warn(
856
+ `getUserHomeDirectory: stderr is not empty: ${stderr}, stdout: ${stdout}, will get a default home: ${home}`,
857
+ );
769
858
 
770
859
  return home;
771
860
  }
@@ -789,14 +878,10 @@ export type SshPlConfig = {
789
878
 
790
879
  export type LockProcessInfo = { pid: number; user: string };
791
880
 
792
- const defaultSshPlConfig: Pick<
793
- SshPlConfig,
794
- | 'useGlobalAccess'
795
- | 'plBinary'
796
- > = {
881
+ const defaultSshPlConfig: Pick<SshPlConfig, "useGlobalAccess" | "plBinary"> = {
797
882
  useGlobalAccess: false,
798
883
  plBinary: {
799
- type: 'Download',
884
+ type: "Download",
800
885
  version: getDefaultPlVersion(),
801
886
  },
802
887
  };
@@ -821,19 +906,19 @@ type DownloadAndUntarState = {
821
906
  };
822
907
 
823
908
  type PlatformaInitStep =
824
- 'init'
825
- | 'detectArch'
826
- | 'detectHome'
827
- | 'checkAlive'
828
- | 'stopExistedPlatforma'
829
- | 'checkDbLock'
830
- | 'downloadBinaries'
831
- | 'fetchPorts'
832
- | 'generateNewConfig'
833
- | 'createFoldersAndSaveFiles'
834
- | 'configureSupervisord'
835
- | 'saveNewConnectionInfo'
836
- | 'startPlatforma';
909
+ | "init"
910
+ | "detectArch"
911
+ | "detectHome"
912
+ | "checkAlive"
913
+ | "stopExistedPlatforma"
914
+ | "checkDbLock"
915
+ | "downloadBinaries"
916
+ | "fetchPorts"
917
+ | "generateNewConfig"
918
+ | "createFoldersAndSaveFiles"
919
+ | "configureSupervisord"
920
+ | "saveNewConnectionInfo"
921
+ | "startPlatforma";
837
922
 
838
923
  type PlatformaInitState = {
839
924
  step: PlatformaInitStep;
@@ -858,9 +943,9 @@ type PlatformaInitState = {
858
943
  * @returns The glibc version as a number
859
944
  * @throws Error if version cannot be determined
860
945
  */
861
- async function getGlibcVersion(logger: MiLogger, sshClient: SshClient): Promise <number> {
946
+ async function getGlibcVersion(logger: MiLogger, sshClient: SshClient): Promise<number> {
862
947
  try {
863
- const { stdout, stderr } = await sshClient.exec('ldd --version | head -n 1');
948
+ const { stdout, stderr } = await sshClient.exec("ldd --version | head -n 1");
864
949
  if (stderr) {
865
950
  throw new Error(`Failed to check glibc version: ${stderr}`);
866
951
  }