@milaboratories/pl-deployments 1.2.2 → 1.2.4
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 +17 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +633 -603
- package/dist/index.mjs.map +1 -1
- package/dist/ssh/pl.d.ts +4 -1
- package/dist/ssh/pl.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/common/pl_binary_download.ts +1 -1
- package/src/ssh/__tests__/ssh-docker.test.ts +1 -1
- package/src/ssh/pl.test.ts +26 -0
- package/src/ssh/pl.ts +84 -7
- package/src/ssh/ssh.ts +5 -5
package/dist/index.mjs
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var w = (
|
|
4
|
-
import { spawn as
|
|
5
|
-
import { sleep as
|
|
1
|
+
var Y = Object.defineProperty;
|
|
2
|
+
var Q = (n, e, r) => e in n ? Y(n, e, { enumerable: !0, configurable: !0, writable: !0, value: r }) : n[e] = r;
|
|
3
|
+
var w = (n, e, r) => Q(n, typeof e != "symbol" ? e + "" : e, r);
|
|
4
|
+
import { spawn as X } from "node:child_process";
|
|
5
|
+
import { sleep as F, fileExists as y, assertNever as H, notEmpty as f, RetryablePromise as tt } from "@milaboratories/ts-helpers";
|
|
6
6
|
import D from "node:fs";
|
|
7
|
-
import m, { readFile as
|
|
8
|
-
import
|
|
9
|
-
import { request as
|
|
10
|
-
import { Readable as
|
|
11
|
-
import { text as
|
|
7
|
+
import m, { readFile as rt } from "node:fs/promises";
|
|
8
|
+
import u from "upath";
|
|
9
|
+
import { request as et } from "undici";
|
|
10
|
+
import { Readable as it, Writable as ot } from "node:stream";
|
|
11
|
+
import { text as nt } from "node:stream/consumers";
|
|
12
12
|
import * as st from "tar";
|
|
13
|
-
import
|
|
13
|
+
import at from "decompress";
|
|
14
14
|
import A from "node:os";
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import { randomBytes as
|
|
19
|
-
import { generateSshPlConfigs as
|
|
15
|
+
import ct, { Client as b } from "ssh2";
|
|
16
|
+
import G from "node:net";
|
|
17
|
+
import lt from "node:dns";
|
|
18
|
+
import { randomBytes as k } from "node:crypto";
|
|
19
|
+
import { generateSshPlConfigs as ht, getFreePort as v } from "@milaboratories/pl-config";
|
|
20
20
|
import { z as p } from "zod";
|
|
21
|
-
function
|
|
22
|
-
return
|
|
23
|
-
cmd: ${JSON.stringify([
|
|
24
|
-
wd: ${
|
|
21
|
+
function dt(n, e) {
|
|
22
|
+
return n.info(`Running:
|
|
23
|
+
cmd: ${JSON.stringify([e.cmd, ...e.args])}
|
|
24
|
+
wd: ${e.opts.cwd}`), n.info(" spawning child process"), X(e.cmd, e.args, e.opts);
|
|
25
25
|
}
|
|
26
|
-
async function
|
|
26
|
+
async function x(n) {
|
|
27
27
|
try {
|
|
28
|
-
return process.kill(
|
|
28
|
+
return process.kill(n, 0), !0;
|
|
29
29
|
} catch {
|
|
30
30
|
return !1;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
function
|
|
34
|
-
return process.kill(
|
|
33
|
+
function M(n) {
|
|
34
|
+
return process.kill(n, "SIGINT");
|
|
35
35
|
}
|
|
36
|
-
async function
|
|
37
|
-
let
|
|
38
|
-
for (; await
|
|
39
|
-
if (await
|
|
40
|
-
throw new Error(`The process did not stopped after ${
|
|
36
|
+
async function J(n, e) {
|
|
37
|
+
let t = 0;
|
|
38
|
+
for (; await x(n); )
|
|
39
|
+
if (await F(100), t += 100, t > e)
|
|
40
|
+
throw new Error(`The process did not stopped after ${e} ms.`);
|
|
41
41
|
}
|
|
42
|
-
const
|
|
43
|
-
function
|
|
44
|
-
switch (
|
|
42
|
+
const ut = ["linux", "macos", "windows"];
|
|
43
|
+
function O(n) {
|
|
44
|
+
switch (n.toLowerCase()) {
|
|
45
45
|
case "darwin":
|
|
46
46
|
return "macos";
|
|
47
47
|
case "linux":
|
|
@@ -50,13 +50,13 @@ function k(s) {
|
|
|
50
50
|
return "windows";
|
|
51
51
|
default:
|
|
52
52
|
throw new Error(
|
|
53
|
-
`operating system '${
|
|
53
|
+
`operating system '${n}' is not currently supported by Platforma ecosystem. The list of OSes supported: ` + JSON.stringify(ut)
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
-
const
|
|
58
|
-
function
|
|
59
|
-
switch (
|
|
57
|
+
const wt = ["amd64", "arm64"];
|
|
58
|
+
function P(n) {
|
|
59
|
+
switch (n) {
|
|
60
60
|
case "aarch64":
|
|
61
61
|
case "aarch64_be":
|
|
62
62
|
case "arm64":
|
|
@@ -66,92 +66,92 @@ function S(s) {
|
|
|
66
66
|
return "amd64";
|
|
67
67
|
default:
|
|
68
68
|
throw new Error(
|
|
69
|
-
`processor architecture '${
|
|
69
|
+
`processor architecture '${n}' is not currently supported by Platforma ecosystem. The list of architectures supported: ` + JSON.stringify(wt)
|
|
70
70
|
);
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
const
|
|
74
|
-
async function
|
|
75
|
-
const
|
|
73
|
+
const ft = "https://cdn.platforma.bio/software", pt = "https://cdn-ga.pl-open.science/software";
|
|
74
|
+
async function mt(n, e, r, t, i, o) {
|
|
75
|
+
const s = L(r, t, e, P(i), O(o)), { archiveUrl: a, alternativeArchiveGAUrl: c, archivePath: l } = s;
|
|
76
76
|
try {
|
|
77
|
-
await C(
|
|
77
|
+
await C(n, a, l), s.wasDownloadedFrom = a;
|
|
78
78
|
} catch {
|
|
79
|
-
await C(
|
|
79
|
+
await C(n, c, l), s.wasDownloadedFrom = c;
|
|
80
80
|
}
|
|
81
|
-
return
|
|
81
|
+
return s;
|
|
82
82
|
}
|
|
83
|
-
async function
|
|
84
|
-
const
|
|
83
|
+
async function gt(n, e, r, t, i, o) {
|
|
84
|
+
const s = L(r, t, e, P(i), O(o)), { archiveUrl: a, alternativeArchiveGAUrl: c, archivePath: l, archiveType: h, targetFolder: d, baseName: $ } = s;
|
|
85
85
|
try {
|
|
86
|
-
await C(
|
|
86
|
+
await C(n, a, l), s.wasDownloadedFrom = a;
|
|
87
87
|
} catch {
|
|
88
|
-
await C(
|
|
88
|
+
await C(n, c, l), s.wasDownloadedFrom = c;
|
|
89
89
|
}
|
|
90
|
-
return await
|
|
90
|
+
return await $t(n, l, h, d), s;
|
|
91
91
|
}
|
|
92
|
-
function
|
|
93
|
-
const o = `${
|
|
92
|
+
function L(n, e, r, t, i) {
|
|
93
|
+
const o = `${e}-${t}`, s = vt[i], a = `${o}.${s}`, c = `${ft}/${n}/${i}/${a}`, l = `${pt}/${n}/${i}/${a}`, h = u.join(r, a), d = u.join(r, o);
|
|
94
94
|
return {
|
|
95
|
-
archiveUrl:
|
|
95
|
+
archiveUrl: c,
|
|
96
96
|
alternativeArchiveGAUrl: l,
|
|
97
97
|
archivePath: h,
|
|
98
|
-
archiveType:
|
|
99
|
-
targetFolder:
|
|
98
|
+
archiveType: s,
|
|
99
|
+
targetFolder: d,
|
|
100
100
|
baseName: o
|
|
101
101
|
};
|
|
102
102
|
}
|
|
103
|
-
async function C(
|
|
104
|
-
const
|
|
105
|
-
|
|
103
|
+
async function C(n, e, r) {
|
|
104
|
+
const t = {};
|
|
105
|
+
t.dstArchive = r;
|
|
106
106
|
try {
|
|
107
|
-
if (
|
|
108
|
-
return
|
|
109
|
-
await m.mkdir(
|
|
110
|
-
URL: ${
|
|
111
|
-
Save to: ${
|
|
112
|
-
const { body: i, statusCode: o } = await
|
|
113
|
-
if (
|
|
114
|
-
const
|
|
115
|
-
throw
|
|
107
|
+
if (t.fileExisted = await y(r), t.fileExisted)
|
|
108
|
+
return n.info(`Platforma Backend archive download skipped: '${r}' already exists`), t;
|
|
109
|
+
await m.mkdir(u.dirname(r), { recursive: !0 }), t.dirnameCreated = !0, n.info(`Downloading archive:
|
|
110
|
+
URL: ${e}
|
|
111
|
+
Save to: ${r}`);
|
|
112
|
+
const { body: i, statusCode: o } = await et(e);
|
|
113
|
+
if (t.statusCode = o, o != 200) {
|
|
114
|
+
const s = await nt(i);
|
|
115
|
+
throw t.errorMsg = `failed to download archive: ${o}, response: ${s.slice(0, 1e3)}`, n.error(t.errorMsg), new Error(t.errorMsg);
|
|
116
116
|
}
|
|
117
|
-
return
|
|
117
|
+
return t.tmpPath = r + ".tmp", await it.toWeb(i).pipeTo(ot.toWeb(D.createWriteStream(t.tmpPath))), t.wroteTmp = !0, t.tmpExisted = await y(t.tmpPath), await m.rename(t.tmpPath, r), t.renamed = !0, t.newExisted = await y(r), t;
|
|
118
118
|
} catch (i) {
|
|
119
|
-
const o = `downloadArchive:
|
|
120
|
-
throw
|
|
119
|
+
const o = `downloadArchive: ${JSON.stringify(i)}, state: ${JSON.stringify(t)}`;
|
|
120
|
+
throw n.error(o), new Error(o);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
|
-
const
|
|
124
|
-
async function
|
|
125
|
-
if (
|
|
126
|
-
const o = `Platforma Backend binary archive not found at '${
|
|
127
|
-
throw
|
|
123
|
+
const yt = ".ok";
|
|
124
|
+
async function $t(n, e, r, t) {
|
|
125
|
+
if (n.info("extracting archive..."), n.info(` archive path: '${e}'`), n.info(` target dir: '${t}'`), !await y(e)) {
|
|
126
|
+
const o = `Platforma Backend binary archive not found at '${e}'`;
|
|
127
|
+
throw n.error(o), new Error(o);
|
|
128
128
|
}
|
|
129
|
-
const i =
|
|
129
|
+
const i = u.join(t, yt);
|
|
130
130
|
if (await y(i)) {
|
|
131
|
-
|
|
131
|
+
n.info(`Platforma Backend binaries unpack skipped: '${t}' exists`);
|
|
132
132
|
return;
|
|
133
133
|
}
|
|
134
|
-
switch (await y(
|
|
134
|
+
switch (await y(t) && (n.info(`Removing previous incompletely unpacked folder: '${t}'`), await m.rm(t, { recursive: !0 })), n.info(` creating target dir '${t}'`), await m.mkdir(t, { recursive: !0 }), n.info(
|
|
135
135
|
`Unpacking Platforma Backend archive:
|
|
136
|
-
Archive: ${
|
|
137
|
-
Target dir: ${
|
|
138
|
-
),
|
|
136
|
+
Archive: ${e}
|
|
137
|
+
Target dir: ${t}`
|
|
138
|
+
), r) {
|
|
139
139
|
case "tgz":
|
|
140
140
|
await st.x({
|
|
141
|
-
file:
|
|
142
|
-
cwd:
|
|
141
|
+
file: e,
|
|
142
|
+
cwd: t,
|
|
143
143
|
gzip: !0
|
|
144
144
|
});
|
|
145
145
|
break;
|
|
146
146
|
case "zip":
|
|
147
|
-
await
|
|
147
|
+
await at(e, t);
|
|
148
148
|
break;
|
|
149
149
|
default:
|
|
150
|
-
|
|
150
|
+
H(r);
|
|
151
151
|
}
|
|
152
|
-
await m.writeFile(i, "ok"),
|
|
152
|
+
await m.writeFile(i, "ok"), n.info(" ... unpack done.");
|
|
153
153
|
}
|
|
154
|
-
const
|
|
154
|
+
const vt = {
|
|
155
155
|
linux: "tgz",
|
|
156
156
|
macos: "tgz",
|
|
157
157
|
windows: "zip"
|
|
@@ -159,87 +159,87 @@ const $t = {
|
|
|
159
159
|
function R() {
|
|
160
160
|
return "1.24.0";
|
|
161
161
|
}
|
|
162
|
-
function
|
|
162
|
+
function St() {
|
|
163
163
|
return { type: "Download", version: R() };
|
|
164
164
|
}
|
|
165
|
-
async function Pt(
|
|
166
|
-
switch (
|
|
165
|
+
async function Pt(n, e, r) {
|
|
166
|
+
switch (r.type) {
|
|
167
167
|
case "Download":
|
|
168
|
-
const
|
|
169
|
-
return
|
|
168
|
+
const t = await gt(n, e, "pl", `pl-${r.version}`, A.arch(), A.platform());
|
|
169
|
+
return u.join(t.baseName, "binaries", Ct[O(A.platform())]);
|
|
170
170
|
case "Local":
|
|
171
|
-
return
|
|
171
|
+
return r.path;
|
|
172
172
|
default:
|
|
173
|
-
|
|
173
|
+
H(r);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
|
-
const
|
|
176
|
+
const Ct = {
|
|
177
177
|
linux: "platforma",
|
|
178
178
|
macos: "platforma",
|
|
179
179
|
windows: "platforma.exe"
|
|
180
180
|
};
|
|
181
|
-
function
|
|
182
|
-
return
|
|
181
|
+
function W(n) {
|
|
182
|
+
return u.join(n, "pl_pid");
|
|
183
183
|
}
|
|
184
|
-
async function
|
|
185
|
-
if (!await y(
|
|
184
|
+
async function Et(n) {
|
|
185
|
+
if (!await y(n))
|
|
186
186
|
return;
|
|
187
|
-
const
|
|
188
|
-
return Number(
|
|
187
|
+
const e = await m.readFile(n);
|
|
188
|
+
return Number(e.toString());
|
|
189
189
|
}
|
|
190
|
-
async function
|
|
191
|
-
await m.writeFile(
|
|
190
|
+
async function At(n, e) {
|
|
191
|
+
await m.writeFile(n, JSON.stringify(e));
|
|
192
192
|
}
|
|
193
|
-
function
|
|
193
|
+
function bt() {
|
|
194
194
|
return {};
|
|
195
195
|
}
|
|
196
|
-
function Ft(
|
|
197
|
-
return
|
|
196
|
+
function Ft(n, e, r) {
|
|
197
|
+
return n[e] = r, r;
|
|
198
198
|
}
|
|
199
|
-
async function N(
|
|
200
|
-
const
|
|
199
|
+
async function N(n, e) {
|
|
200
|
+
const r = bt();
|
|
201
201
|
try {
|
|
202
|
-
return await
|
|
203
|
-
} catch (
|
|
204
|
-
throw
|
|
202
|
+
return await e((i, o) => Ft(r, i, o), r);
|
|
203
|
+
} catch (t) {
|
|
204
|
+
throw n.error(`error ${t} while doing traced operation, state: ${JSON.stringify(r)}`), t;
|
|
205
205
|
}
|
|
206
206
|
}
|
|
207
|
-
const
|
|
208
|
-
class
|
|
209
|
-
constructor(r, t,
|
|
207
|
+
const Dt = "config-local.yaml";
|
|
208
|
+
class kt {
|
|
209
|
+
constructor(e, r, t, i, o, s, a, c) {
|
|
210
210
|
w(this, "instance");
|
|
211
211
|
w(this, "pid");
|
|
212
212
|
w(this, "nRuns", 0);
|
|
213
213
|
w(this, "lastRunHistory", {});
|
|
214
214
|
w(this, "wasStopped", !1);
|
|
215
|
-
this.logger =
|
|
215
|
+
this.logger = e, this.workingDir = r, this.startOptions = t, this.initialStartHistory = i, this.onClose = o, this.onError = s, this.onCloseAndError = a, this.onCloseAndErrorNoStop = c;
|
|
216
216
|
}
|
|
217
217
|
async start() {
|
|
218
|
-
await N(this.logger, async (
|
|
218
|
+
await N(this.logger, async (e, r) => {
|
|
219
219
|
this.wasStopped = !1;
|
|
220
|
-
const
|
|
221
|
-
|
|
220
|
+
const t = dt(this.logger, this.startOptions);
|
|
221
|
+
t.on("error", (o) => {
|
|
222
222
|
this.logger.error(
|
|
223
223
|
`error '${o}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`
|
|
224
224
|
), this.onError !== void 0 && this.onError(this), this.onCloseAndError !== void 0 && this.onCloseAndError(this), this.onCloseAndErrorNoStop !== void 0 && !this.wasStopped && this.onCloseAndErrorNoStop(this);
|
|
225
|
-
}),
|
|
225
|
+
}), t.on("close", () => {
|
|
226
226
|
this.logger.warn(`platforma was closed, started opts: ${JSON.stringify(this.debugInfo())}`), this.onClose !== void 0 && this.onClose(this), this.onCloseAndError !== void 0 && this.onCloseAndError(this), this.onCloseAndErrorNoStop !== void 0 && !this.wasStopped && this.onCloseAndErrorNoStop(this);
|
|
227
|
-
}),
|
|
228
|
-
const i =
|
|
229
|
-
|
|
227
|
+
}), e("started", !0);
|
|
228
|
+
const i = e("pidFile", W(this.workingDir));
|
|
229
|
+
e("pid", f(t.pid)), e("pidWritten", await At(i, f(t.pid))), this.nRuns++, this.instance = t, this.pid = t.pid, this.lastRunHistory = r;
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
stop() {
|
|
233
|
-
this.wasStopped = !0,
|
|
233
|
+
this.wasStopped = !0, M(f(this.pid));
|
|
234
234
|
}
|
|
235
235
|
async waitStopped() {
|
|
236
|
-
await
|
|
236
|
+
await J(f(this.pid), 15e3);
|
|
237
237
|
}
|
|
238
238
|
stopped() {
|
|
239
239
|
return this.wasStopped;
|
|
240
240
|
}
|
|
241
241
|
async isAlive() {
|
|
242
|
-
return await
|
|
242
|
+
return await x(f(this.pid));
|
|
243
243
|
}
|
|
244
244
|
debugInfo() {
|
|
245
245
|
return {
|
|
@@ -252,53 +252,53 @@ class Dt {
|
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
|
-
async function
|
|
256
|
-
const
|
|
257
|
-
plBinary:
|
|
255
|
+
async function gr(n, e) {
|
|
256
|
+
const r = {
|
|
257
|
+
plBinary: St(),
|
|
258
258
|
spawnOptions: {},
|
|
259
259
|
closeOld: !0,
|
|
260
|
-
...
|
|
260
|
+
...e
|
|
261
261
|
};
|
|
262
|
-
return await N(
|
|
263
|
-
|
|
264
|
-
const o =
|
|
265
|
-
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
const
|
|
269
|
-
cmd:
|
|
270
|
-
args: ["--config",
|
|
262
|
+
return await N(n, async (t, i) => {
|
|
263
|
+
t("startOptions", { ...r, config: "too wordy" });
|
|
264
|
+
const o = u.resolve(r.workingDir);
|
|
265
|
+
r.closeOld && t("closeOld", await xt(n, o));
|
|
266
|
+
const s = u.join(o, Dt);
|
|
267
|
+
n.info(`writing configuration '${s}'...`), await m.writeFile(s, r.config);
|
|
268
|
+
const a = u.join(o, "binaries"), c = await Pt(n, a, r.plBinary), h = {
|
|
269
|
+
cmd: t("binaryPath", u.join("binaries", c)),
|
|
270
|
+
args: ["--config", s],
|
|
271
271
|
opts: {
|
|
272
272
|
env: { ...process.env },
|
|
273
273
|
cwd: o,
|
|
274
274
|
stdio: ["pipe", "ignore", "inherit"],
|
|
275
275
|
windowsHide: !0,
|
|
276
276
|
// hide a terminal on Windows
|
|
277
|
-
...
|
|
277
|
+
...r.spawnOptions
|
|
278
278
|
}
|
|
279
279
|
};
|
|
280
|
-
|
|
280
|
+
t("processOpts", {
|
|
281
281
|
cmd: h.cmd,
|
|
282
282
|
args: h.args,
|
|
283
283
|
cwd: h.opts.cwd
|
|
284
284
|
});
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
285
|
+
const d = new kt(
|
|
286
|
+
n,
|
|
287
|
+
r.workingDir,
|
|
288
288
|
h,
|
|
289
289
|
i,
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
290
|
+
r.onClose,
|
|
291
|
+
r.onError,
|
|
292
|
+
r.onCloseAndError,
|
|
293
|
+
r.onCloseAndErrorNoStop
|
|
294
294
|
);
|
|
295
|
-
return await
|
|
295
|
+
return await d.start(), d;
|
|
296
296
|
});
|
|
297
297
|
}
|
|
298
|
-
async function xt(
|
|
299
|
-
return await N(
|
|
300
|
-
const i =
|
|
301
|
-
return o !== void 0 &&
|
|
298
|
+
async function xt(n, e) {
|
|
299
|
+
return await N(n, async (r, t) => {
|
|
300
|
+
const i = r("pidFilePath", W(e)), o = r("pid", await Et(i)), s = r("wasAlive", await x(o));
|
|
301
|
+
return o !== void 0 && s && (r("stopped", M(o)), r("waitStopped", await J(o, 1e4))), t;
|
|
302
302
|
});
|
|
303
303
|
}
|
|
304
304
|
const Ot = {
|
|
@@ -306,60 +306,60 @@ const Ot = {
|
|
|
306
306
|
keepaliveCountMax: 10
|
|
307
307
|
};
|
|
308
308
|
class B {
|
|
309
|
-
constructor(
|
|
309
|
+
constructor(e, r) {
|
|
310
310
|
w(this, "config");
|
|
311
311
|
w(this, "homeDir");
|
|
312
312
|
w(this, "forwardedServers", []);
|
|
313
|
-
this.logger =
|
|
313
|
+
this.logger = e, this.client = r;
|
|
314
314
|
}
|
|
315
315
|
/**
|
|
316
316
|
* Initializes the SshClient and establishes a connection using the provided configuration.
|
|
317
317
|
* @param config - The connection configuration object for the SSH client.
|
|
318
318
|
* @returns A new instance of SshClient with an active connection.
|
|
319
319
|
*/
|
|
320
|
-
static async init(
|
|
321
|
-
const
|
|
320
|
+
static async init(e, r) {
|
|
321
|
+
const t = {
|
|
322
322
|
...Ot,
|
|
323
|
-
...
|
|
324
|
-
}, i = new B(
|
|
325
|
-
return await i.connect(
|
|
323
|
+
...r
|
|
324
|
+
}, i = new B(e, new b());
|
|
325
|
+
return await i.connect(t), i;
|
|
326
326
|
}
|
|
327
327
|
getForwardedServers() {
|
|
328
328
|
return this.forwardedServers;
|
|
329
329
|
}
|
|
330
330
|
getFullHostName() {
|
|
331
|
-
var
|
|
332
|
-
return `${(
|
|
331
|
+
var e, r;
|
|
332
|
+
return `${(e = this.config) == null ? void 0 : e.host}:${(r = this.config) == null ? void 0 : r.port}`;
|
|
333
333
|
}
|
|
334
334
|
getUserName() {
|
|
335
|
-
var
|
|
336
|
-
return (
|
|
335
|
+
var e;
|
|
336
|
+
return (e = this.config) == null ? void 0 : e.username;
|
|
337
337
|
}
|
|
338
338
|
/**
|
|
339
339
|
* Connects to the SSH server using the specified configuration.
|
|
340
340
|
* @param config - The connection configuration object for the SSH client.
|
|
341
341
|
* @returns A promise that resolves when the connection is established or rejects on error.
|
|
342
342
|
*/
|
|
343
|
-
async connect(
|
|
344
|
-
return this.config =
|
|
343
|
+
async connect(e) {
|
|
344
|
+
return this.config = e, await Rt(this.client, e);
|
|
345
345
|
}
|
|
346
346
|
/**
|
|
347
347
|
* Executes a command on the SSH server.
|
|
348
348
|
* @param command - The command to execute on the remote server.
|
|
349
349
|
* @returns A promise resolving with the command's stdout and stderr outputs.
|
|
350
350
|
*/
|
|
351
|
-
async exec(
|
|
352
|
-
return new Promise((
|
|
353
|
-
this.client.exec(
|
|
351
|
+
async exec(e) {
|
|
352
|
+
return new Promise((r, t) => {
|
|
353
|
+
this.client.exec(e, (i, o) => {
|
|
354
354
|
if (i)
|
|
355
|
-
return
|
|
356
|
-
let
|
|
357
|
-
o.on("close", (
|
|
358
|
-
|
|
359
|
-
}).on("data", (
|
|
360
|
-
|
|
361
|
-
}).stderr.on("data", (
|
|
362
|
-
|
|
355
|
+
return t(`ssh.exec: ${e}: ${i}`);
|
|
356
|
+
let s = "", a = "";
|
|
357
|
+
o.on("close", (c) => {
|
|
358
|
+
c === 0 ? r({ stdout: s, stderr: a }) : t(new Error(`Command ${e} exited with code ${c}, stdout: ${s}, stderr: ${a}`));
|
|
359
|
+
}).on("data", (c) => {
|
|
360
|
+
s += c.toString();
|
|
361
|
+
}).stderr.on("data", (c) => {
|
|
362
|
+
a += c.toString();
|
|
363
363
|
});
|
|
364
364
|
});
|
|
365
365
|
});
|
|
@@ -370,22 +370,22 @@ class B {
|
|
|
370
370
|
* @param port - The port number to connect to on the server.
|
|
371
371
|
* @returns 'publickey' | 'password'[] A promise resolving with a list of supported authentication methods.
|
|
372
372
|
*/
|
|
373
|
-
static async getAuthTypes(
|
|
374
|
-
return new Promise((
|
|
373
|
+
static async getAuthTypes(e, r) {
|
|
374
|
+
return new Promise((t) => {
|
|
375
375
|
let i = "";
|
|
376
|
-
const o = new
|
|
376
|
+
const o = new b();
|
|
377
377
|
o.on("ready", () => {
|
|
378
378
|
o.end();
|
|
379
|
-
const
|
|
380
|
-
|
|
379
|
+
const s = this.extractAuthMethods(i);
|
|
380
|
+
t(s.length === 0 ? ["publickey", "password"] : s);
|
|
381
381
|
}), o.on("error", () => {
|
|
382
|
-
o.end(),
|
|
382
|
+
o.end(), t(["publickey", "password"]);
|
|
383
383
|
}), o.connect({
|
|
384
|
-
host:
|
|
385
|
-
port:
|
|
384
|
+
host: e,
|
|
385
|
+
port: r,
|
|
386
386
|
username: (/* @__PURE__ */ new Date()).getTime().toString(),
|
|
387
|
-
debug: (
|
|
388
|
-
i += `${
|
|
387
|
+
debug: (s) => {
|
|
388
|
+
i += `${s}
|
|
389
389
|
`;
|
|
390
390
|
}
|
|
391
391
|
});
|
|
@@ -396,9 +396,9 @@ class B {
|
|
|
396
396
|
* @param log - The debug log output containing authentication information.
|
|
397
397
|
* @returns An array of extracted authentication methods.
|
|
398
398
|
*/
|
|
399
|
-
static extractAuthMethods(
|
|
400
|
-
const
|
|
401
|
-
return
|
|
399
|
+
static extractAuthMethods(e) {
|
|
400
|
+
const r = e.match(/Inbound: Received USERAUTH_FAILURE \((.+)\)/);
|
|
401
|
+
return r && r[1] ? r[1].split(",").map((t) => t.trim()) : [];
|
|
402
402
|
}
|
|
403
403
|
/**
|
|
404
404
|
* Sets up port forwarding between a remote port on the SSH server and a local port.
|
|
@@ -407,62 +407,62 @@ class B {
|
|
|
407
407
|
* @param config - Optional connection configuration for the SSH client.
|
|
408
408
|
* @returns { server: net.Server } A promise resolving with the created server instance.
|
|
409
409
|
*/
|
|
410
|
-
async forwardPort(
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
const i = new
|
|
414
|
-
const
|
|
415
|
-
|
|
416
|
-
this.logger.info(`${
|
|
417
|
-
}),
|
|
418
|
-
this.logger.info(`${
|
|
419
|
-
}),
|
|
420
|
-
this.logger.info(`${
|
|
421
|
-
}),
|
|
410
|
+
async forwardPort(e, r) {
|
|
411
|
+
const t = `ssh.forward:${e.localPort}:${e.remotePort}.id_${k(1).toString("hex")}`;
|
|
412
|
+
r = r ?? this.config;
|
|
413
|
+
const i = new tt((o) => new Promise((s, a) => {
|
|
414
|
+
const c = new b();
|
|
415
|
+
c.on("ready", () => {
|
|
416
|
+
this.logger.info(`${t}.client.ready`), s(c);
|
|
417
|
+
}), c.on("error", (l) => {
|
|
418
|
+
this.logger.info(`${t}.client.error: ${l}`), o.reset(), a(l);
|
|
419
|
+
}), c.on("close", () => {
|
|
420
|
+
this.logger.info(`${t}.client.closed`), o.reset();
|
|
421
|
+
}), c.connect(r);
|
|
422
422
|
}));
|
|
423
|
-
return await i.ensure(), new Promise((o,
|
|
424
|
-
const
|
|
425
|
-
const l = `${
|
|
423
|
+
return await i.ensure(), new Promise((o, s) => {
|
|
424
|
+
const a = G.createServer({ pauseOnConnect: !0 }, async (c) => {
|
|
425
|
+
const l = `${t}.sock_${k(1).toString("hex")}`;
|
|
426
426
|
let h;
|
|
427
427
|
try {
|
|
428
428
|
h = await i.ensure();
|
|
429
429
|
} catch ($) {
|
|
430
|
-
this.logger.info(`${l}.persistentClient.catch: ${$}`),
|
|
430
|
+
this.logger.info(`${l}.persistentClient.catch: ${$}`), c.end();
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
|
-
h.setNoDelay(!0),
|
|
434
|
-
let
|
|
433
|
+
h.setNoDelay(!0), c.setNoDelay(!0);
|
|
434
|
+
let d;
|
|
435
435
|
try {
|
|
436
|
-
|
|
436
|
+
d = await Nt(this.logger, h, "127.0.0.1", 0, "127.0.0.1", e.remotePort);
|
|
437
437
|
} catch ($) {
|
|
438
|
-
this.logger.error(`${l}.forwardOut.err: ${$}`),
|
|
438
|
+
this.logger.error(`${l}.forwardOut.err: ${$}`), c.end();
|
|
439
439
|
return;
|
|
440
440
|
}
|
|
441
|
-
|
|
442
|
-
this.logger.error(`${l}.stream.error: ${$}`),
|
|
443
|
-
}),
|
|
444
|
-
|
|
445
|
-
}),
|
|
446
|
-
this.logger.info(`${l}.localSocket: closed`),
|
|
441
|
+
c.pipe(d), d.pipe(c), c.resume(), d.on("error", ($) => {
|
|
442
|
+
this.logger.error(`${l}.stream.error: ${$}`), c.end(), d.end();
|
|
443
|
+
}), d.on("close", () => {
|
|
444
|
+
c.end(), d.end();
|
|
445
|
+
}), c.on("close", () => {
|
|
446
|
+
this.logger.info(`${l}.localSocket: closed`), c.end(), d.end();
|
|
447
447
|
});
|
|
448
448
|
});
|
|
449
|
-
|
|
450
|
-
this.logger.info(`${
|
|
451
|
-
}),
|
|
452
|
-
|
|
453
|
-
}),
|
|
454
|
-
this.logger.info(`${
|
|
449
|
+
a.listen(e.localPort, "127.0.0.1", () => {
|
|
450
|
+
this.logger.info(`${t}.server: started listening`), this.forwardedServers.push(a), o({ server: a });
|
|
451
|
+
}), a.on("error", (c) => {
|
|
452
|
+
a.close(), s(new Error(`${t}.server: error: ${JSON.stringify(c)}`));
|
|
453
|
+
}), a.on("close", () => {
|
|
454
|
+
this.logger.info(`${t}.server: closed ${JSON.stringify(e)}`), this.forwardedServers = this.forwardedServers.filter((c) => c !== a);
|
|
455
455
|
});
|
|
456
456
|
});
|
|
457
457
|
}
|
|
458
458
|
closeForwardedPorts() {
|
|
459
|
-
this.logger.info("[SSH] Closing all forwarded ports..."), this.forwardedServers.forEach((
|
|
460
|
-
const
|
|
461
|
-
if (
|
|
462
|
-
const
|
|
463
|
-
this.logger.info(`[SSH] Closing port forward for server ${
|
|
459
|
+
this.logger.info("[SSH] Closing all forwarded ports..."), this.forwardedServers.forEach((e) => {
|
|
460
|
+
const r = e.address();
|
|
461
|
+
if (r && typeof r != "string") {
|
|
462
|
+
const t = r;
|
|
463
|
+
this.logger.info(`[SSH] Closing port forward for server ${t.address}:${t.port}`);
|
|
464
464
|
}
|
|
465
|
-
|
|
465
|
+
e.close();
|
|
466
466
|
}), this.forwardedServers = [];
|
|
467
467
|
}
|
|
468
468
|
/**
|
|
@@ -470,10 +470,10 @@ class B {
|
|
|
470
470
|
* @param hostname - The hostname or IP address to check.
|
|
471
471
|
* @returns A promise resolving with `true` if the host is reachable, otherwise `false`.
|
|
472
472
|
*/
|
|
473
|
-
static async checkHostAvailability(
|
|
474
|
-
return new Promise((
|
|
475
|
-
|
|
476
|
-
|
|
473
|
+
static async checkHostAvailability(e) {
|
|
474
|
+
return new Promise((r) => {
|
|
475
|
+
lt.lookup(e, (t) => {
|
|
476
|
+
r(!t);
|
|
477
477
|
});
|
|
478
478
|
});
|
|
479
479
|
}
|
|
@@ -482,12 +482,12 @@ class B {
|
|
|
482
482
|
* @param privateKey - The private key content to check.
|
|
483
483
|
* @returns A promise resolving with `true` if a passphrase is required, otherwise `false`.
|
|
484
484
|
*/
|
|
485
|
-
static async isPassphraseRequiredForKey(
|
|
486
|
-
return new Promise((
|
|
485
|
+
static async isPassphraseRequiredForKey(e) {
|
|
486
|
+
return new Promise((r, t) => {
|
|
487
487
|
try {
|
|
488
|
-
return
|
|
488
|
+
return ct.utils.parseKey(e) instanceof Error && r(!0), r(!1);
|
|
489
489
|
} catch (i) {
|
|
490
|
-
console.log("Error parsing privateKey"),
|
|
490
|
+
console.log("Error parsing privateKey"), t(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`));
|
|
491
491
|
}
|
|
492
492
|
});
|
|
493
493
|
}
|
|
@@ -498,156 +498,156 @@ class B {
|
|
|
498
498
|
* @param remotePath - The remote file path on the server.
|
|
499
499
|
* @returns A promise resolving with `true` if the file was successfully uploaded.
|
|
500
500
|
*/
|
|
501
|
-
async uploadFile(
|
|
502
|
-
return await this.withSftp(async (
|
|
503
|
-
|
|
504
|
-
if (
|
|
505
|
-
const
|
|
506
|
-
`ssh.uploadFile: err: ${
|
|
501
|
+
async uploadFile(e, r) {
|
|
502
|
+
return await this.withSftp(async (t) => new Promise((i, o) => {
|
|
503
|
+
t.fastPut(e, r, (s) => {
|
|
504
|
+
if (s) {
|
|
505
|
+
const a = new Error(
|
|
506
|
+
`ssh.uploadFile: err: ${s}, localPath: ${e}, remotePath: ${r}`
|
|
507
507
|
);
|
|
508
|
-
return o(
|
|
508
|
+
return o(a);
|
|
509
509
|
}
|
|
510
510
|
i(!0);
|
|
511
511
|
});
|
|
512
512
|
}));
|
|
513
513
|
}
|
|
514
|
-
async withSftp(
|
|
515
|
-
return new Promise((
|
|
514
|
+
async withSftp(e) {
|
|
515
|
+
return new Promise((r, t) => {
|
|
516
516
|
this.client.sftp((i, o) => {
|
|
517
517
|
if (i)
|
|
518
|
-
return
|
|
519
|
-
|
|
520
|
-
|
|
518
|
+
return t(new Error(`ssh.withSftp: sftp err: ${i}`));
|
|
519
|
+
e(o).then(r).catch((s) => {
|
|
520
|
+
t(new Error(`ssh.withSftp.callback: err ${s}`));
|
|
521
521
|
}).finally(() => {
|
|
522
522
|
o == null || o.end();
|
|
523
523
|
});
|
|
524
524
|
});
|
|
525
525
|
});
|
|
526
526
|
}
|
|
527
|
-
async writeFileOnTheServer(r, t
|
|
528
|
-
return this.withSftp(async (i) => this.writeFile(i, r, t
|
|
527
|
+
async writeFileOnTheServer(e, r, t = 432) {
|
|
528
|
+
return this.withSftp(async (i) => this.writeFile(i, e, r, t));
|
|
529
529
|
}
|
|
530
|
-
async getForderStructure(r, t
|
|
530
|
+
async getForderStructure(e, r, t = { files: [], directories: [] }) {
|
|
531
531
|
return new Promise((i, o) => {
|
|
532
|
-
|
|
533
|
-
if (
|
|
534
|
-
return o(
|
|
535
|
-
for (const
|
|
536
|
-
const l = `${
|
|
537
|
-
if (
|
|
538
|
-
|
|
532
|
+
e.readdir(r, async (s, a) => {
|
|
533
|
+
if (s)
|
|
534
|
+
return o(s);
|
|
535
|
+
for (const c of a) {
|
|
536
|
+
const l = `${r}/${c.filename}`;
|
|
537
|
+
if (c.attrs.isDirectory()) {
|
|
538
|
+
t.directories.push(l);
|
|
539
539
|
try {
|
|
540
|
-
await this.getForderStructure(
|
|
540
|
+
await this.getForderStructure(e, l, t);
|
|
541
541
|
} catch (h) {
|
|
542
542
|
return o(h);
|
|
543
543
|
}
|
|
544
544
|
} else
|
|
545
|
-
|
|
545
|
+
t.files.push(l);
|
|
546
546
|
}
|
|
547
|
-
i(
|
|
547
|
+
i(t);
|
|
548
548
|
});
|
|
549
549
|
});
|
|
550
550
|
}
|
|
551
|
-
rmdir(
|
|
552
|
-
return new Promise((
|
|
553
|
-
|
|
551
|
+
rmdir(e, r) {
|
|
552
|
+
return new Promise((t, i) => {
|
|
553
|
+
e.rmdir(r, (o) => o ? i(o) : t(!0));
|
|
554
554
|
});
|
|
555
555
|
}
|
|
556
|
-
unlink(
|
|
557
|
-
return new Promise((
|
|
558
|
-
|
|
556
|
+
unlink(e, r) {
|
|
557
|
+
return new Promise((t, i) => {
|
|
558
|
+
e.unlink(r, (o) => o ? i(o) : t(!0));
|
|
559
559
|
});
|
|
560
560
|
}
|
|
561
|
-
async deleteFolder(
|
|
562
|
-
return this.withSftp(async (
|
|
561
|
+
async deleteFolder(e) {
|
|
562
|
+
return this.withSftp(async (r) => {
|
|
563
563
|
try {
|
|
564
|
-
const
|
|
565
|
-
this.logger.info("ssh.deleteFolder list of files and directories"), this.logger.info(`ssh.deleteFolder list of files: ${
|
|
566
|
-
for (const i of
|
|
567
|
-
this.logger.info(`ssh.deleteFolder unlink file ${i}`), await this.unlink(
|
|
568
|
-
|
|
569
|
-
for (const i of
|
|
570
|
-
this.logger.info(`ssh.deleteFolder rmdir ${i}`), await this.rmdir(
|
|
571
|
-
return await this.rmdir(
|
|
572
|
-
} catch (
|
|
573
|
-
this.logger.error(
|
|
574
|
-
const i =
|
|
575
|
-
throw new Error(`ssh.deleteFolder: path: ${
|
|
564
|
+
const t = await this.getForderStructure(r, e);
|
|
565
|
+
this.logger.info("ssh.deleteFolder list of files and directories"), this.logger.info(`ssh.deleteFolder list of files: ${t.files}`), this.logger.info(`ssh.deleteFolder list of directories: ${t.directories}`);
|
|
566
|
+
for (const i of t.files)
|
|
567
|
+
this.logger.info(`ssh.deleteFolder unlink file ${i}`), await this.unlink(r, i);
|
|
568
|
+
t.directories.sort((i, o) => o.length - i.length);
|
|
569
|
+
for (const i of t.directories)
|
|
570
|
+
this.logger.info(`ssh.deleteFolder rmdir ${i}`), await this.rmdir(r, i);
|
|
571
|
+
return await this.rmdir(r, e), !0;
|
|
572
|
+
} catch (t) {
|
|
573
|
+
this.logger.error(t);
|
|
574
|
+
const i = t instanceof Error ? t.message : "";
|
|
575
|
+
throw new Error(`ssh.deleteFolder: path: ${e}, message: ${i}`);
|
|
576
576
|
}
|
|
577
577
|
});
|
|
578
578
|
}
|
|
579
|
-
async readFile(
|
|
580
|
-
return this.withSftp(async (
|
|
581
|
-
|
|
579
|
+
async readFile(e) {
|
|
580
|
+
return this.withSftp(async (r) => new Promise((t, i) => {
|
|
581
|
+
r.readFile(e, (o, s) => {
|
|
582
582
|
if (o)
|
|
583
|
-
return i(new Error(`ssh.readFile:
|
|
584
|
-
|
|
583
|
+
return i(new Error(`ssh.readFile: ${o}`));
|
|
584
|
+
t(s.toString());
|
|
585
585
|
});
|
|
586
586
|
}));
|
|
587
587
|
}
|
|
588
|
-
async chmod(
|
|
589
|
-
return this.withSftp(async (
|
|
590
|
-
|
|
588
|
+
async chmod(e, r) {
|
|
589
|
+
return this.withSftp(async (t) => new Promise((i, o) => {
|
|
590
|
+
t.chmod(e, r, (s) => s ? o(new Error(`ssh.chmod: ${s}, path: ${e}, mode: ${r}`)) : i(void 0));
|
|
591
591
|
}));
|
|
592
592
|
}
|
|
593
|
-
async checkFileExists(
|
|
594
|
-
return this.withSftp(async (
|
|
595
|
-
|
|
593
|
+
async checkFileExists(e) {
|
|
594
|
+
return this.withSftp(async (r) => new Promise((t, i) => {
|
|
595
|
+
r.stat(e, (o, s) => {
|
|
596
596
|
if (o)
|
|
597
|
-
return (o == null ? void 0 : o.code) === 2 ?
|
|
598
|
-
|
|
597
|
+
return (o == null ? void 0 : o.code) === 2 ? t(!1) : i(new Error(`ssh.checkFileExists: err ${o}`));
|
|
598
|
+
t(s.isFile());
|
|
599
599
|
});
|
|
600
600
|
}));
|
|
601
601
|
}
|
|
602
|
-
async checkPathExists(
|
|
603
|
-
return this.withSftp(async (
|
|
604
|
-
|
|
602
|
+
async checkPathExists(e) {
|
|
603
|
+
return this.withSftp(async (r) => new Promise((t, i) => {
|
|
604
|
+
r.stat(e, (o, s) => {
|
|
605
605
|
if (o)
|
|
606
|
-
return o.code === 2 ?
|
|
607
|
-
|
|
606
|
+
return o.code === 2 ? t({ exists: !1, isFile: !1, isDirectory: !1 }) : i(new Error(`ssh.checkPathExists: ${o}`));
|
|
607
|
+
t({
|
|
608
608
|
exists: !0,
|
|
609
|
-
isFile:
|
|
610
|
-
isDirectory:
|
|
609
|
+
isFile: s.isFile(),
|
|
610
|
+
isDirectory: s.isDirectory()
|
|
611
611
|
});
|
|
612
612
|
});
|
|
613
613
|
}));
|
|
614
614
|
}
|
|
615
|
-
async writeFile(r, t,
|
|
616
|
-
return new Promise((o,
|
|
617
|
-
|
|
618
|
-
if (
|
|
619
|
-
return
|
|
615
|
+
async writeFile(e, r, t, i = 432) {
|
|
616
|
+
return new Promise((o, s) => {
|
|
617
|
+
e.writeFile(r, t, { mode: i }, (a) => {
|
|
618
|
+
if (a)
|
|
619
|
+
return s(new Error(`ssh.writeFile: err ${a}, remotePath: ${r}`));
|
|
620
620
|
o(!0);
|
|
621
621
|
});
|
|
622
622
|
});
|
|
623
623
|
}
|
|
624
|
-
uploadFileUsingExistingSftp(r, t,
|
|
625
|
-
return new Promise((o,
|
|
626
|
-
|
|
627
|
-
this.writeFile(
|
|
624
|
+
uploadFileUsingExistingSftp(e, r, t, i = 432) {
|
|
625
|
+
return new Promise((o, s) => {
|
|
626
|
+
rt(r).then(async (a) => {
|
|
627
|
+
this.writeFile(e, t, a, i).then(() => {
|
|
628
628
|
o(void 0);
|
|
629
|
-
}).catch((
|
|
630
|
-
const l = `uploadFileUsingExistingSftp:
|
|
631
|
-
this.logger.error(l),
|
|
629
|
+
}).catch((c) => {
|
|
630
|
+
const l = `uploadFileUsingExistingSftp: ${c}`;
|
|
631
|
+
this.logger.error(l), s(new Error(l));
|
|
632
632
|
});
|
|
633
633
|
});
|
|
634
634
|
});
|
|
635
635
|
}
|
|
636
|
-
async __uploadDirectory(r, t,
|
|
637
|
-
return new Promise((o,
|
|
638
|
-
D.readdir(
|
|
639
|
-
if (
|
|
640
|
-
return
|
|
636
|
+
async __uploadDirectory(e, r, t, i = 432) {
|
|
637
|
+
return new Promise((o, s) => {
|
|
638
|
+
D.readdir(r, async (a, c) => {
|
|
639
|
+
if (a)
|
|
640
|
+
return s(new Error(`ssh.__uploadDir: err ${a}, localDir: ${r}, remoteDir: ${t}`));
|
|
641
641
|
try {
|
|
642
|
-
await this.__createRemoteDirectory(
|
|
643
|
-
for (const l of
|
|
644
|
-
const h =
|
|
645
|
-
D.lstatSync(h).isDirectory() ? await this.__uploadDirectory(
|
|
642
|
+
await this.__createRemoteDirectory(e, t);
|
|
643
|
+
for (const l of c) {
|
|
644
|
+
const h = u.join(r, l), d = `${t}/${l}`;
|
|
645
|
+
D.lstatSync(h).isDirectory() ? await this.__uploadDirectory(e, h, d, i) : await this.uploadFileUsingExistingSftp(e, h, d, i);
|
|
646
646
|
}
|
|
647
647
|
o();
|
|
648
648
|
} catch (l) {
|
|
649
649
|
const h = `ssh.__uploadDir: catched err ${l}`;
|
|
650
|
-
this.logger.error(h),
|
|
650
|
+
this.logger.error(h), s(new Error(h));
|
|
651
651
|
}
|
|
652
652
|
});
|
|
653
653
|
});
|
|
@@ -658,13 +658,13 @@ class B {
|
|
|
658
658
|
* @param remoteDir - The path to the remote directory on the server.
|
|
659
659
|
* @returns A promise that resolves when the directory and its contents are uploaded.
|
|
660
660
|
*/
|
|
661
|
-
async uploadDirectory(r, t
|
|
661
|
+
async uploadDirectory(e, r, t = 432) {
|
|
662
662
|
return new Promise((i, o) => {
|
|
663
|
-
this.withSftp(async (
|
|
663
|
+
this.withSftp(async (s) => {
|
|
664
664
|
try {
|
|
665
|
-
await this.__uploadDirectory(
|
|
666
|
-
} catch (
|
|
667
|
-
o(new Error(`ssh.uploadDirectory: ${
|
|
665
|
+
await this.__uploadDirectory(s, e, r, t), i();
|
|
666
|
+
} catch (a) {
|
|
667
|
+
o(new Error(`ssh.uploadDirectory: ${a}`));
|
|
668
668
|
}
|
|
669
669
|
});
|
|
670
670
|
});
|
|
@@ -675,22 +675,22 @@ class B {
|
|
|
675
675
|
* @param remotePath - The path to the remote directory.
|
|
676
676
|
* @returns A promise that resolves when the directory is created.
|
|
677
677
|
*/
|
|
678
|
-
__createRemoteDirectory(
|
|
679
|
-
return new Promise((
|
|
680
|
-
const o =
|
|
681
|
-
let
|
|
682
|
-
const
|
|
683
|
-
if (
|
|
684
|
-
return
|
|
685
|
-
|
|
686
|
-
l ?
|
|
678
|
+
__createRemoteDirectory(e, r) {
|
|
679
|
+
return new Promise((t, i) => {
|
|
680
|
+
const o = r.split("/");
|
|
681
|
+
let s = "";
|
|
682
|
+
const a = (c) => {
|
|
683
|
+
if (c >= o.length)
|
|
684
|
+
return t();
|
|
685
|
+
s += `${o[c]}/`, e.stat(s, (l) => {
|
|
686
|
+
l ? e.mkdir(s, (h) => {
|
|
687
687
|
if (h)
|
|
688
|
-
return i(new Error(`ssh.__createRemDir: err ${h}, remotePath: ${
|
|
689
|
-
c
|
|
690
|
-
}) : c
|
|
688
|
+
return i(new Error(`ssh.__createRemDir: err ${h}, remotePath: ${r}`));
|
|
689
|
+
a(c + 1);
|
|
690
|
+
}) : a(c + 1);
|
|
691
691
|
});
|
|
692
692
|
};
|
|
693
|
-
|
|
693
|
+
a(0);
|
|
694
694
|
});
|
|
695
695
|
}
|
|
696
696
|
/**
|
|
@@ -699,25 +699,25 @@ class B {
|
|
|
699
699
|
* @param remotePath - The path to the remote directory.
|
|
700
700
|
* @returns A promise that resolves when the directory is created.
|
|
701
701
|
*/
|
|
702
|
-
ensureRemoteDirCreated(
|
|
703
|
-
return this.withSftp(async (
|
|
704
|
-
const i =
|
|
702
|
+
ensureRemoteDirCreated(e, r = 493) {
|
|
703
|
+
return this.withSftp(async (t) => {
|
|
704
|
+
const i = e.split("/");
|
|
705
705
|
let o = "";
|
|
706
|
-
for (const
|
|
707
|
-
o += `${
|
|
706
|
+
for (const s of i) {
|
|
707
|
+
o += `${s}/`;
|
|
708
708
|
try {
|
|
709
|
-
await new Promise((
|
|
710
|
-
|
|
711
|
-
if (!l) return
|
|
712
|
-
|
|
709
|
+
await new Promise((a, c) => {
|
|
710
|
+
t.stat(o, (l) => {
|
|
711
|
+
if (!l) return a();
|
|
712
|
+
t.mkdir(o, { mode: r }, (h) => {
|
|
713
713
|
if (h)
|
|
714
|
-
return
|
|
715
|
-
|
|
714
|
+
return c(new Error(`ssh.createRemoteDir: err ${h}, remotePath: ${e}`));
|
|
715
|
+
a();
|
|
716
716
|
});
|
|
717
717
|
});
|
|
718
718
|
});
|
|
719
|
-
} catch (
|
|
720
|
-
throw console.error(`Failed to create directory: ${o}`,
|
|
719
|
+
} catch (a) {
|
|
720
|
+
throw console.error(`Failed to create directory: ${o}`, a), a;
|
|
721
721
|
}
|
|
722
722
|
}
|
|
723
723
|
});
|
|
@@ -728,11 +728,11 @@ class B {
|
|
|
728
728
|
* @param localPath - The local file path to save the file.
|
|
729
729
|
* @returns A promise resolving with `true` if the file was successfully downloaded.
|
|
730
730
|
*/
|
|
731
|
-
async downloadFile(
|
|
732
|
-
return this.withSftp(async (
|
|
733
|
-
|
|
734
|
-
if (
|
|
735
|
-
return o(new Error(`ssh.downloadFile: err ${
|
|
731
|
+
async downloadFile(e, r) {
|
|
732
|
+
return this.withSftp(async (t) => new Promise((i, o) => {
|
|
733
|
+
t.fastGet(e, r, (s) => {
|
|
734
|
+
if (s)
|
|
735
|
+
return o(new Error(`ssh.downloadFile: err ${s}, remotePath: ${e}, localPath: ${r}`));
|
|
736
736
|
i(!0);
|
|
737
737
|
});
|
|
738
738
|
}));
|
|
@@ -744,167 +744,168 @@ class B {
|
|
|
744
744
|
this.closeForwardedPorts(), this.client.end();
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
|
-
async function
|
|
747
|
+
async function Rt(n, e, r, t) {
|
|
748
748
|
return new Promise((i, o) => {
|
|
749
|
-
|
|
750
|
-
i(
|
|
751
|
-
}),
|
|
752
|
-
o(new Error(`ssh.connect:
|
|
753
|
-
}),
|
|
754
|
-
}),
|
|
749
|
+
n.on("ready", () => {
|
|
750
|
+
i(n);
|
|
751
|
+
}), n.on("error", (s) => {
|
|
752
|
+
o(new Error(`ssh.connect: ${s}`));
|
|
753
|
+
}), n.on("close", () => {
|
|
754
|
+
}), n.connect(e), n.setNoDelay(!0);
|
|
755
755
|
});
|
|
756
756
|
}
|
|
757
|
-
async function
|
|
758
|
-
return new Promise((
|
|
759
|
-
|
|
757
|
+
async function Nt(n, e, r, t, i, o) {
|
|
758
|
+
return new Promise((s, a) => {
|
|
759
|
+
e.forwardOut(r, t, i, o, (c, l) => c ? (n.error(`forwardOut.error: ${c}`), a(c)) : s(l));
|
|
760
760
|
});
|
|
761
761
|
}
|
|
762
|
-
const
|
|
763
|
-
function g(
|
|
764
|
-
return
|
|
762
|
+
const Bt = "minio-2024-12-18T13-15-44Z", Ut = "supervisord-0.7.3", Tt = "supervisord_0.7.3_Linux_64-bit";
|
|
763
|
+
function g(n) {
|
|
764
|
+
return u.join(n, ".platforma_ssh");
|
|
765
765
|
}
|
|
766
|
-
function E(
|
|
767
|
-
return
|
|
766
|
+
function E(n) {
|
|
767
|
+
return u.join(g(n), "binaries");
|
|
768
768
|
}
|
|
769
|
-
function
|
|
770
|
-
return
|
|
769
|
+
function It(n, e) {
|
|
770
|
+
return u.join(E(n), `pl-${R()}-${P(e)}`);
|
|
771
771
|
}
|
|
772
|
-
function
|
|
773
|
-
return
|
|
772
|
+
function V(n, e) {
|
|
773
|
+
return u.join(It(n, e), "binaries");
|
|
774
774
|
}
|
|
775
|
-
function T(
|
|
776
|
-
return
|
|
775
|
+
function T(n, e) {
|
|
776
|
+
return u.join(V(n, e), "platforma");
|
|
777
777
|
}
|
|
778
|
-
function
|
|
779
|
-
return
|
|
778
|
+
function _t(n, e) {
|
|
779
|
+
return u.join(V(n, e), "free-port");
|
|
780
780
|
}
|
|
781
|
-
function
|
|
782
|
-
return
|
|
781
|
+
function q(n, e) {
|
|
782
|
+
return u.join(E(n), `minio-2024-12-18T13-15-44Z-${P(e)}`);
|
|
783
783
|
}
|
|
784
|
-
function
|
|
785
|
-
return
|
|
784
|
+
function jt(n, e) {
|
|
785
|
+
return u.join(q(n, e), "minio");
|
|
786
786
|
}
|
|
787
|
-
function
|
|
788
|
-
return
|
|
787
|
+
function Ht(n, e) {
|
|
788
|
+
return u.join(E(n), `supervisord-0.7.3-${P(e)}`, Tt);
|
|
789
789
|
}
|
|
790
|
-
function
|
|
791
|
-
return
|
|
790
|
+
function z(n, e) {
|
|
791
|
+
return u.join(Ht(n, e), "supervisord");
|
|
792
792
|
}
|
|
793
|
-
function
|
|
794
|
-
return
|
|
793
|
+
function K(n) {
|
|
794
|
+
return u.join(g(n), "supervisor.conf");
|
|
795
795
|
}
|
|
796
|
-
function I(
|
|
797
|
-
return
|
|
796
|
+
function I(n) {
|
|
797
|
+
return u.join(g(n), "connection.txt");
|
|
798
798
|
}
|
|
799
|
-
async function
|
|
800
|
-
const
|
|
801
|
-
if (
|
|
802
|
-
throw new Error(`Can not run ssh Platforma ${
|
|
799
|
+
async function Gt(n, e, r) {
|
|
800
|
+
const t = await U(n, e, r, "--daemon");
|
|
801
|
+
if (t.stderr)
|
|
802
|
+
throw new Error(`Can not run ssh Platforma ${t.stderr}`);
|
|
803
803
|
}
|
|
804
|
-
async function
|
|
805
|
-
const
|
|
806
|
-
if (
|
|
807
|
-
throw new Error(`Can not stop ssh Platforma ${
|
|
804
|
+
async function Mt(n, e, r) {
|
|
805
|
+
const t = await U(n, e, r, "ctl shutdown");
|
|
806
|
+
if (t.stderr)
|
|
807
|
+
throw new Error(`Can not stop ssh Platforma ${t.stderr}`);
|
|
808
808
|
}
|
|
809
|
-
async function
|
|
809
|
+
async function Jt(n, e, r, t) {
|
|
810
810
|
let i;
|
|
811
811
|
try {
|
|
812
|
-
i = await U(r, t,
|
|
813
|
-
} catch (
|
|
814
|
-
return { execError: String(
|
|
812
|
+
i = await U(e, r, t, "ctl status");
|
|
813
|
+
} catch (c) {
|
|
814
|
+
return { execError: String(c), allAlive: !1 };
|
|
815
815
|
}
|
|
816
816
|
if (i.stderr)
|
|
817
|
-
return
|
|
818
|
-
const o = _(i.stdout, "platforma"),
|
|
817
|
+
return n.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`), { rawResult: i, allAlive: !1 };
|
|
818
|
+
const o = _(i.stdout, "platforma"), s = _(i.stdout, "minio"), a = {
|
|
819
819
|
rawResult: i,
|
|
820
820
|
platforma: o,
|
|
821
|
-
minio:
|
|
822
|
-
allAlive: o &&
|
|
821
|
+
minio: s,
|
|
822
|
+
allAlive: o && s
|
|
823
823
|
};
|
|
824
|
-
return
|
|
824
|
+
return a.allAlive || (a.minio || n.warn("Minio is not running on the server"), a.platforma || n.warn("Platforma is not running on the server")), a;
|
|
825
825
|
}
|
|
826
|
-
function
|
|
827
|
-
const
|
|
826
|
+
function Lt(n, e, r, t, i, o, s) {
|
|
827
|
+
const a = Object.entries(e).map(([h, d]) => `${h}="${d}"`).join(","), c = k(16).toString("hex"), l = r;
|
|
828
828
|
return `
|
|
829
829
|
[supervisord]
|
|
830
|
-
logfile=${
|
|
830
|
+
logfile=${t}/supervisord.log
|
|
831
831
|
loglevel=info
|
|
832
|
-
pidfile=${
|
|
832
|
+
pidfile=${t}/supervisord.pid
|
|
833
833
|
|
|
834
834
|
[inet_http_server]
|
|
835
835
|
port=127.0.0.1:${l}
|
|
836
836
|
username=default-user
|
|
837
|
-
password=${
|
|
837
|
+
password=${c}
|
|
838
838
|
|
|
839
839
|
[supervisorctl]
|
|
840
840
|
serverurl=http://127.0.0.1:${l}
|
|
841
841
|
username=default-user
|
|
842
|
-
password=${
|
|
842
|
+
password=${c}
|
|
843
843
|
|
|
844
844
|
[program:platforma]
|
|
845
845
|
autostart=true
|
|
846
846
|
depends_on=minio
|
|
847
|
-
command=${
|
|
848
|
-
directory=${
|
|
847
|
+
command=${s} --config ${i}
|
|
848
|
+
directory=${t}
|
|
849
849
|
autorestart=true
|
|
850
850
|
|
|
851
851
|
[program:minio]
|
|
852
852
|
autostart=true
|
|
853
|
-
environment=${
|
|
854
|
-
command=${o} server ${
|
|
855
|
-
directory=${
|
|
853
|
+
environment=${a}
|
|
854
|
+
command=${o} server ${n}
|
|
855
|
+
directory=${t}
|
|
856
856
|
autorestart=true
|
|
857
857
|
`;
|
|
858
858
|
}
|
|
859
|
-
async function U(
|
|
860
|
-
const i =
|
|
861
|
-
return await
|
|
859
|
+
async function U(n, e, r, t) {
|
|
860
|
+
const i = z(e, r), o = K(e), s = `${i} --configuration ${o} ${t}`;
|
|
861
|
+
return await n.exec(s);
|
|
862
862
|
}
|
|
863
|
-
function _(
|
|
864
|
-
return ((i) => i.replace(/\x1B\[[0-9;]*m/g, ""))(
|
|
863
|
+
function _(n, e) {
|
|
864
|
+
return ((i) => i.replace(/\x1B\[[0-9;]*m/g, ""))(n).split(`
|
|
865
865
|
`).some((i) => {
|
|
866
|
-
const [o,
|
|
867
|
-
return o ===
|
|
866
|
+
const [o, s] = i.trim().split(/\s{2,}/);
|
|
867
|
+
return o === e && s === "Running";
|
|
868
868
|
});
|
|
869
869
|
}
|
|
870
|
-
const
|
|
870
|
+
const S = p.object({
|
|
871
871
|
local: p.number(),
|
|
872
872
|
remote: p.number()
|
|
873
|
-
}), Lt = p.object({
|
|
874
|
-
grpc: P,
|
|
875
|
-
monitoring: P,
|
|
876
|
-
debug: P,
|
|
877
|
-
minioPort: P,
|
|
878
|
-
minioConsolePort: P
|
|
879
873
|
}), Wt = p.object({
|
|
874
|
+
grpc: S,
|
|
875
|
+
monitoring: S,
|
|
876
|
+
debug: S,
|
|
877
|
+
minioPort: S,
|
|
878
|
+
minioConsolePort: S
|
|
879
|
+
}), Vt = p.object({
|
|
880
880
|
plUser: p.string(),
|
|
881
881
|
plPassword: p.string(),
|
|
882
|
-
ports:
|
|
882
|
+
ports: Wt,
|
|
883
883
|
// It's false by default because it was added later,
|
|
884
884
|
// and in some deployments there won't be useGlobalAccess flag in the file.
|
|
885
885
|
useGlobalAccess: p.boolean().default(!1),
|
|
886
886
|
// We added the field afterwards, the pl backend was this version.
|
|
887
887
|
plVersion: p.string().default("1.18.3")
|
|
888
888
|
});
|
|
889
|
-
function
|
|
889
|
+
function qt(n, e, r, t, i) {
|
|
890
890
|
return {
|
|
891
|
-
plUser:
|
|
892
|
-
plPassword:
|
|
893
|
-
ports:
|
|
894
|
-
useGlobalAccess:
|
|
891
|
+
plUser: n,
|
|
892
|
+
plPassword: e,
|
|
893
|
+
ports: r,
|
|
894
|
+
useGlobalAccess: t,
|
|
895
895
|
plVersion: i
|
|
896
896
|
};
|
|
897
897
|
}
|
|
898
|
-
function
|
|
899
|
-
return
|
|
898
|
+
function zt(n) {
|
|
899
|
+
return Vt.parse(JSON.parse(n));
|
|
900
900
|
}
|
|
901
|
-
function
|
|
902
|
-
return JSON.stringify(
|
|
901
|
+
function Kt(n) {
|
|
902
|
+
return JSON.stringify(n, void 0, 2);
|
|
903
903
|
}
|
|
904
|
-
|
|
905
|
-
|
|
904
|
+
const j = 2.28;
|
|
905
|
+
class Z {
|
|
906
|
+
constructor(e, r, t) {
|
|
906
907
|
w(this, "initState", {});
|
|
907
|
-
this.logger =
|
|
908
|
+
this.logger = e, this.sshClient = r, this.username = t;
|
|
908
909
|
}
|
|
909
910
|
info() {
|
|
910
911
|
return {
|
|
@@ -912,12 +913,12 @@ class q {
|
|
|
912
913
|
initState: this.initState
|
|
913
914
|
};
|
|
914
915
|
}
|
|
915
|
-
static async init(
|
|
916
|
+
static async init(e, r) {
|
|
916
917
|
try {
|
|
917
|
-
const
|
|
918
|
-
return new
|
|
919
|
-
} catch (
|
|
920
|
-
throw
|
|
918
|
+
const t = await B.init(e, r);
|
|
919
|
+
return new Z(e, t, f(r.username));
|
|
920
|
+
} catch (t) {
|
|
921
|
+
throw e.error(`Connection error in SshClient.init: ${t}`), t;
|
|
921
922
|
}
|
|
922
923
|
}
|
|
923
924
|
cleanUp() {
|
|
@@ -925,30 +926,30 @@ class q {
|
|
|
925
926
|
}
|
|
926
927
|
/** Provides an info if the platforma and minio are running along with the debug info. */
|
|
927
928
|
async isAlive() {
|
|
928
|
-
const
|
|
929
|
-
return await
|
|
929
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
930
|
+
return await Jt(this.logger, this.sshClient, r, e.arch);
|
|
930
931
|
}
|
|
931
932
|
/** Starts all the services on the server.
|
|
932
933
|
* Idempotent semantic: we could call it several times. */
|
|
933
934
|
async start() {
|
|
934
|
-
const
|
|
935
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
935
936
|
try {
|
|
936
937
|
if (!(await this.isAlive()).allAlive)
|
|
937
|
-
return await
|
|
938
|
-
} catch (
|
|
939
|
-
const i = `SshPl.start:
|
|
938
|
+
return await Gt(this.sshClient, r, e.arch), await this.checkIsAliveWithInterval();
|
|
939
|
+
} catch (t) {
|
|
940
|
+
const i = `SshPl.start: ${t}`;
|
|
940
941
|
throw this.logger.error(i), new Error(i);
|
|
941
942
|
}
|
|
942
943
|
}
|
|
943
944
|
/** Stops all the services on the server.
|
|
944
945
|
* Idempotent semantic: we could call it several times. */
|
|
945
946
|
async stop() {
|
|
946
|
-
const
|
|
947
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
947
948
|
try {
|
|
948
949
|
if ((await this.isAlive()).allAlive)
|
|
949
|
-
return await
|
|
950
|
-
} catch (
|
|
951
|
-
const i = `PlSsh.stop:
|
|
950
|
+
return await Mt(this.sshClient, r, e.arch), await this.checkIsAliveWithInterval(void 0, void 0, !1);
|
|
951
|
+
} catch (t) {
|
|
952
|
+
const i = `PlSsh.stop: ${t}`;
|
|
952
953
|
throw this.logger.error(i), new Error(i);
|
|
953
954
|
}
|
|
954
955
|
}
|
|
@@ -958,118 +959,125 @@ class q {
|
|
|
958
959
|
}
|
|
959
960
|
/** Stops platforma and deletes its state. */
|
|
960
961
|
async stopAndClean() {
|
|
961
|
-
const
|
|
962
|
-
this.logger.info("pl.reset: Stop Platforma on the server"), await this.stop(), this.logger.info(`pl.reset: Deleting Platforma workDir ${g(
|
|
962
|
+
const e = await this.getUserHomeDirectory();
|
|
963
|
+
this.logger.info("pl.reset: Stop Platforma on the server"), await this.stop(), this.logger.info(`pl.reset: Deleting Platforma workDir ${g(e)} on the server`), await this.sshClient.deleteFolder(g(e));
|
|
963
964
|
}
|
|
964
965
|
/** Downloads binaries and untar them on the server,
|
|
965
966
|
* generates all the configs, creates necessary dirs,
|
|
966
967
|
* and finally starts all the services. */
|
|
967
|
-
async platformaInit(
|
|
968
|
-
const
|
|
968
|
+
async platformaInit(e) {
|
|
969
|
+
const r = { localWorkdir: e.localWorkdir }, { onProgress: t } = e;
|
|
969
970
|
try {
|
|
970
|
-
const
|
|
971
|
-
...
|
|
972
|
-
...
|
|
971
|
+
const i = {
|
|
972
|
+
...Zt,
|
|
973
|
+
...e
|
|
973
974
|
};
|
|
974
|
-
if (
|
|
975
|
-
if (
|
|
975
|
+
if (r.plBinaryOps = i.plBinary, await (t == null ? void 0 : t("Detecting server architecture...")), r.arch = await this.getArch(), await (t == null ? void 0 : t("Server architecture detected.")), await (t == null ? void 0 : t("Fetching user home directory...")), r.remoteHome = await this.getUserHomeDirectory(), await (t == null ? void 0 : t("User home directory retrieved.")), await (t == null ? void 0 : t("Checking platform status...")), r.alive = await this.isAlive(), r.alive.allAlive && await (t == null ? void 0 : t("All required services are running.")), r.alive.allAlive) {
|
|
976
|
+
if (r.userCredentials = await this.getUserCredentials(r.remoteHome), !r.userCredentials)
|
|
976
977
|
throw new Error("SshPl.platformaInit: platforma is alive but userCredentials are not found");
|
|
977
|
-
const
|
|
978
|
-
if (
|
|
979
|
-
return t.userCredentials;
|
|
980
|
-
await this.stop();
|
|
978
|
+
const h = r.userCredentials.useGlobalAccess == i.useGlobalAccess, d = r.userCredentials.plVersion == i.plBinary.version;
|
|
979
|
+
if (r.needRestart = !(h && d), this.logger.info(`SshPl.platformaInit: need restart? ${r.needRestart}`), !r.needRestart)
|
|
980
|
+
return await (t == null ? void 0 : t("Server setup completed.")), r.userCredentials;
|
|
981
|
+
await (t == null ? void 0 : t("Stopping services...")), await this.stop();
|
|
981
982
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
983
|
+
await (t == null ? void 0 : t("Downloading and uploading required binaries..."));
|
|
984
|
+
const o = await Yt(this.logger, this.sshClient);
|
|
985
|
+
if (o < j)
|
|
986
|
+
throw new Error(`glibc version ${o} is too old. Version ${j} or higher is required for Platforma.`);
|
|
987
|
+
const s = await this.downloadBinariesAndUploadToTheServer(
|
|
988
|
+
i.localWorkdir,
|
|
989
|
+
i.plBinary,
|
|
990
|
+
r.remoteHome,
|
|
991
|
+
r.arch
|
|
987
992
|
);
|
|
988
|
-
if (t.binPaths = { ...
|
|
993
|
+
if (await (t == null ? void 0 : t("All required binaries have been downloaded and uploaded.")), r.binPaths = { ...s, history: void 0 }, r.downloadedBinaries = s.history, r.ports = await this.fetchPorts(r.remoteHome, r.arch), !r.ports.debug.remote || !r.ports.grpc.remote || !r.ports.minioPort.remote || !r.ports.minioConsolePort.remote || !r.ports.monitoring.remote)
|
|
989
994
|
throw new Error("SshPl.platformaInit: remote ports are not defined");
|
|
990
|
-
|
|
995
|
+
await (t == null ? void 0 : t("Generating server configuration..."));
|
|
996
|
+
const a = await ht({
|
|
991
997
|
logger: this.logger,
|
|
992
|
-
workingDir: g(
|
|
998
|
+
workingDir: g(r.remoteHome),
|
|
993
999
|
portsMode: {
|
|
994
1000
|
type: "customWithMinio",
|
|
995
1001
|
ports: {
|
|
996
|
-
debug:
|
|
997
|
-
grpc:
|
|
998
|
-
minio:
|
|
999
|
-
minioConsole:
|
|
1000
|
-
monitoring:
|
|
1001
|
-
grpcLocal:
|
|
1002
|
-
minioLocal:
|
|
1002
|
+
debug: r.ports.debug.remote,
|
|
1003
|
+
grpc: r.ports.grpc.remote,
|
|
1004
|
+
minio: r.ports.minioPort.remote,
|
|
1005
|
+
minioConsole: r.ports.minioConsolePort.remote,
|
|
1006
|
+
monitoring: r.ports.monitoring.remote,
|
|
1007
|
+
grpcLocal: r.ports.grpc.local,
|
|
1008
|
+
minioLocal: r.ports.minioPort.local
|
|
1003
1009
|
}
|
|
1004
1010
|
},
|
|
1005
|
-
licenseMode:
|
|
1006
|
-
useGlobalAccess: f(
|
|
1011
|
+
licenseMode: i.license,
|
|
1012
|
+
useGlobalAccess: f(i.useGlobalAccess),
|
|
1013
|
+
plConfigPostprocessing: i.plConfigPostprocessing
|
|
1007
1014
|
});
|
|
1008
|
-
|
|
1009
|
-
for (const [
|
|
1010
|
-
await this.sshClient.writeFileOnTheServer(
|
|
1011
|
-
for (const
|
|
1012
|
-
await this.sshClient.ensureRemoteDirCreated(
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1015
|
+
r.generatedConfig = { ...a, filesToCreate: { skipped: "it is too wordy" } }, await (t == null ? void 0 : t("Server configuration generated.")), await (t == null ? void 0 : t("Generating folder structure..."));
|
|
1016
|
+
for (const [h, d] of Object.entries(a.filesToCreate))
|
|
1017
|
+
await this.sshClient.writeFileOnTheServer(h, d), this.logger.info(`Created file ${h}`);
|
|
1018
|
+
for (const h of a.dirsToCreate)
|
|
1019
|
+
await this.sshClient.ensureRemoteDirCreated(h), this.logger.info(`Created directory ${h}`);
|
|
1020
|
+
await (t == null ? void 0 : t("Folder structure created.")), await (t == null ? void 0 : t("Writing supervisord configuration..."));
|
|
1021
|
+
const c = Lt(
|
|
1022
|
+
a.minioConfig.storageDir,
|
|
1023
|
+
a.minioConfig.envs,
|
|
1024
|
+
await this.getFreePortForPlatformaOnServer(r.remoteHome, r.arch),
|
|
1025
|
+
a.workingDir,
|
|
1026
|
+
a.plConfig.configPath,
|
|
1027
|
+
r.binPaths.minioRelPath,
|
|
1028
|
+
r.binPaths.downloadedPl
|
|
1021
1029
|
);
|
|
1022
|
-
if (!await this.sshClient.writeFileOnTheServer(
|
|
1023
|
-
throw new Error(`Can not write supervisord config on the server ${g(
|
|
1024
|
-
return t.connectionInfo =
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
f(
|
|
1029
|
-
|
|
1030
|
+
if (!await this.sshClient.writeFileOnTheServer(K(r.remoteHome), c))
|
|
1031
|
+
throw new Error(`Can not write supervisord config on the server ${g(r.remoteHome)}`);
|
|
1032
|
+
return await (t == null ? void 0 : t("Supervisord configuration written.")), await (t == null ? void 0 : t("Saving connection information...")), r.connectionInfo = qt(
|
|
1033
|
+
a.plUser,
|
|
1034
|
+
a.plPassword,
|
|
1035
|
+
r.ports,
|
|
1036
|
+
f(i.useGlobalAccess),
|
|
1037
|
+
i.plBinary.version
|
|
1030
1038
|
), await this.sshClient.writeFileOnTheServer(
|
|
1031
|
-
I(
|
|
1032
|
-
|
|
1033
|
-
), await this.start(),
|
|
1034
|
-
} catch (
|
|
1035
|
-
const
|
|
1036
|
-
throw this.logger.error(
|
|
1039
|
+
I(r.remoteHome),
|
|
1040
|
+
Kt(r.connectionInfo)
|
|
1041
|
+
), await (t == null ? void 0 : t("Connection information saved.")), await (t == null ? void 0 : t("Starting Platforma on the server...")), await this.start(), r.started = !0, this.initState = r, await (t == null ? void 0 : t("Platforma has been started successfully.")), r.connectionInfo;
|
|
1042
|
+
} catch (i) {
|
|
1043
|
+
const o = `SshPl.platformaInit: ${i}, state: ${JSON.stringify(r)}`;
|
|
1044
|
+
throw this.logger.error(o), new Error(o);
|
|
1037
1045
|
}
|
|
1038
1046
|
}
|
|
1039
|
-
async downloadBinariesAndUploadToTheServer(r, t,
|
|
1047
|
+
async downloadBinariesAndUploadToTheServer(e, r, t, i) {
|
|
1040
1048
|
const o = [];
|
|
1041
1049
|
try {
|
|
1042
|
-
const
|
|
1043
|
-
r,
|
|
1050
|
+
const s = await this.downloadAndUntar(
|
|
1044
1051
|
e,
|
|
1052
|
+
t,
|
|
1045
1053
|
i,
|
|
1046
1054
|
"pl",
|
|
1047
|
-
`pl-${
|
|
1055
|
+
`pl-${r.version}`
|
|
1048
1056
|
);
|
|
1049
|
-
o.push(
|
|
1050
|
-
const
|
|
1051
|
-
r,
|
|
1057
|
+
o.push(s);
|
|
1058
|
+
const a = await this.downloadAndUntar(
|
|
1052
1059
|
e,
|
|
1060
|
+
t,
|
|
1053
1061
|
i,
|
|
1054
1062
|
"supervisord",
|
|
1055
|
-
|
|
1063
|
+
Ut
|
|
1056
1064
|
);
|
|
1057
|
-
o.push(
|
|
1058
|
-
const
|
|
1059
|
-
r,
|
|
1065
|
+
o.push(a);
|
|
1066
|
+
const c = jt(t, i.arch), l = await this.downloadAndUntar(
|
|
1060
1067
|
e,
|
|
1068
|
+
t,
|
|
1061
1069
|
i,
|
|
1062
1070
|
"minio",
|
|
1063
|
-
|
|
1071
|
+
Bt
|
|
1064
1072
|
);
|
|
1065
|
-
return o.push(l), await this.sshClient.chmod(
|
|
1073
|
+
return o.push(l), await this.sshClient.chmod(c, 488), {
|
|
1066
1074
|
history: o,
|
|
1067
|
-
minioRelPath:
|
|
1068
|
-
downloadedPl: T(
|
|
1075
|
+
minioRelPath: c,
|
|
1076
|
+
downloadedPl: T(t, i.arch)
|
|
1069
1077
|
};
|
|
1070
|
-
} catch (
|
|
1071
|
-
const
|
|
1072
|
-
throw this.logger.error(
|
|
1078
|
+
} catch (s) {
|
|
1079
|
+
const a = `SshPl.downloadBinariesAndUploadToServer: ${s}, state: ${JSON.stringify(o)}`;
|
|
1080
|
+
throw this.logger.error(a), s;
|
|
1073
1081
|
}
|
|
1074
1082
|
}
|
|
1075
1083
|
/** We have to extract pl in the remote server,
|
|
@@ -1078,129 +1086,151 @@ class q {
|
|
|
1078
1086
|
* For this reason, we extract all to the remote server.
|
|
1079
1087
|
* It requires `tar` to be installed on the server
|
|
1080
1088
|
* (it's not installed for Rocky Linux for example). */
|
|
1081
|
-
async downloadAndUntar(r, t,
|
|
1082
|
-
const
|
|
1083
|
-
|
|
1084
|
-
let
|
|
1085
|
-
const
|
|
1086
|
-
for (let h = 1; h <=
|
|
1089
|
+
async downloadAndUntar(e, r, t, i, o) {
|
|
1090
|
+
const s = {};
|
|
1091
|
+
s.binBasePath = E(r), await this.sshClient.ensureRemoteDirCreated(s.binBasePath), s.binBasePathCreated = !0;
|
|
1092
|
+
let a = null;
|
|
1093
|
+
const c = 5;
|
|
1094
|
+
for (let h = 1; h <= c; h++)
|
|
1087
1095
|
try {
|
|
1088
|
-
|
|
1096
|
+
a = await mt(
|
|
1089
1097
|
this.logger,
|
|
1090
|
-
|
|
1098
|
+
e,
|
|
1091
1099
|
i,
|
|
1092
1100
|
o,
|
|
1093
|
-
|
|
1094
|
-
|
|
1101
|
+
t.arch,
|
|
1102
|
+
t.platform
|
|
1095
1103
|
);
|
|
1096
1104
|
break;
|
|
1097
|
-
} catch (
|
|
1098
|
-
if (await
|
|
1099
|
-
throw new Error(`downloadAndUntar: ${
|
|
1105
|
+
} catch (d) {
|
|
1106
|
+
if (await F(300), h == c)
|
|
1107
|
+
throw new Error(`downloadAndUntar: ${c} attempts, last error: ${d}`);
|
|
1100
1108
|
}
|
|
1101
|
-
|
|
1109
|
+
s.downloadResult = f(a), s.localArchivePath = u.resolve(s.downloadResult.archivePath), s.remoteDir = u.join(s.binBasePath, s.downloadResult.baseName), s.remoteArchivePath = s.remoteDir + ".tgz", await this.sshClient.ensureRemoteDirCreated(s.remoteDir), await this.sshClient.uploadFile(s.localArchivePath, s.remoteArchivePath), s.uploadDone = !0;
|
|
1110
|
+
try {
|
|
1111
|
+
await this.sshClient.exec("hash tar");
|
|
1112
|
+
} catch {
|
|
1113
|
+
throw new Error("tar is not installed on the server. Please install it before running Platforma.");
|
|
1114
|
+
}
|
|
1102
1115
|
const l = await this.sshClient.exec(
|
|
1103
|
-
`tar --warning=no-all -xvf ${
|
|
1116
|
+
`tar --warning=no-all -xvf ${s.remoteArchivePath} --directory=${s.remoteDir}`
|
|
1104
1117
|
);
|
|
1105
1118
|
if (l.stderr)
|
|
1106
|
-
throw Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);
|
|
1107
|
-
return
|
|
1108
|
-
}
|
|
1109
|
-
async needDownload(
|
|
1110
|
-
const
|
|
1111
|
-
return !await this.sshClient.checkFileExists(o) || !await this.sshClient.checkFileExists(i) || !await this.sshClient.checkFileExists(
|
|
1112
|
-
}
|
|
1113
|
-
async checkIsAliveWithInterval(
|
|
1114
|
-
const i =
|
|
1115
|
-
let o = 0,
|
|
1116
|
-
for (;
|
|
1117
|
-
if (await
|
|
1118
|
-
throw new Error(`isAliveWithInterval: The process did not ${
|
|
1119
|
-
|
|
1119
|
+
throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);
|
|
1120
|
+
return s.untarDone = !0, s;
|
|
1121
|
+
}
|
|
1122
|
+
async needDownload(e, r) {
|
|
1123
|
+
const t = z(e, r.arch), i = q(e, r.arch), o = T(e, r.arch);
|
|
1124
|
+
return !await this.sshClient.checkFileExists(o) || !await this.sshClient.checkFileExists(i) || !await this.sshClient.checkFileExists(t);
|
|
1125
|
+
}
|
|
1126
|
+
async checkIsAliveWithInterval(e = 1e3, r = 15, t = !0) {
|
|
1127
|
+
const i = r * e;
|
|
1128
|
+
let o = 0, s = await this.isAlive();
|
|
1129
|
+
for (; t ? !s.allAlive : s.allAlive; ) {
|
|
1130
|
+
if (await F(e), o += e, o > i)
|
|
1131
|
+
throw new Error(`isAliveWithInterval: The process did not ${t ? "started" : "stopped"} after ${i} ms. Live status: ${JSON.stringify(s)}`);
|
|
1132
|
+
s = await this.isAlive();
|
|
1120
1133
|
}
|
|
1121
1134
|
}
|
|
1122
|
-
async getUserCredentials(
|
|
1123
|
-
const
|
|
1124
|
-
return
|
|
1135
|
+
async getUserCredentials(e) {
|
|
1136
|
+
const r = await this.sshClient.readFile(I(e));
|
|
1137
|
+
return zt(r);
|
|
1125
1138
|
}
|
|
1126
|
-
async fetchPorts(
|
|
1139
|
+
async fetchPorts(e, r) {
|
|
1127
1140
|
return {
|
|
1128
1141
|
grpc: {
|
|
1129
1142
|
local: await v(),
|
|
1130
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1143
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1131
1144
|
},
|
|
1132
1145
|
monitoring: {
|
|
1133
1146
|
local: await v(),
|
|
1134
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1147
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1135
1148
|
},
|
|
1136
1149
|
debug: {
|
|
1137
1150
|
local: await v(),
|
|
1138
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1151
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1139
1152
|
},
|
|
1140
1153
|
minioPort: {
|
|
1141
1154
|
local: await v(),
|
|
1142
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1155
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1143
1156
|
},
|
|
1144
1157
|
minioConsolePort: {
|
|
1145
1158
|
local: await v(),
|
|
1146
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1159
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1147
1160
|
}
|
|
1148
1161
|
};
|
|
1149
1162
|
}
|
|
1150
1163
|
async getLocalFreePort() {
|
|
1151
|
-
return new Promise((
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
const
|
|
1155
|
-
|
|
1164
|
+
return new Promise((e) => {
|
|
1165
|
+
const r = G.createServer();
|
|
1166
|
+
r.listen(0, () => {
|
|
1167
|
+
const t = r.address().port;
|
|
1168
|
+
r.close((i) => e(t));
|
|
1156
1169
|
});
|
|
1157
1170
|
});
|
|
1158
1171
|
}
|
|
1159
|
-
async getFreePortForPlatformaOnServer(
|
|
1160
|
-
const
|
|
1172
|
+
async getFreePortForPlatformaOnServer(e, r) {
|
|
1173
|
+
const t = _t(e, r.arch), { stdout: i, stderr: o } = await this.sshClient.exec(`${t}`);
|
|
1161
1174
|
if (o)
|
|
1162
1175
|
throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);
|
|
1163
1176
|
return +i;
|
|
1164
1177
|
}
|
|
1165
1178
|
async getArch() {
|
|
1166
|
-
const { stdout:
|
|
1167
|
-
if (
|
|
1168
|
-
throw new Error(`getArch: stderr is not empty: ${
|
|
1169
|
-
const
|
|
1179
|
+
const { stdout: e, stderr: r } = await this.sshClient.exec("uname -s && uname -m");
|
|
1180
|
+
if (r)
|
|
1181
|
+
throw new Error(`getArch: stderr is not empty: ${r}, stdout: ${e}`);
|
|
1182
|
+
const t = e.split(`
|
|
1170
1183
|
`);
|
|
1171
1184
|
return {
|
|
1172
|
-
platform:
|
|
1173
|
-
arch:
|
|
1185
|
+
platform: t[0],
|
|
1186
|
+
arch: t[1]
|
|
1174
1187
|
};
|
|
1175
1188
|
}
|
|
1176
1189
|
async getUserHomeDirectory() {
|
|
1177
|
-
const { stdout:
|
|
1178
|
-
if (
|
|
1179
|
-
const
|
|
1180
|
-
return console.warn(`getUserHomeDirectory: stderr is not empty: ${
|
|
1190
|
+
const { stdout: e, stderr: r } = await this.sshClient.exec("echo $HOME");
|
|
1191
|
+
if (r) {
|
|
1192
|
+
const t = `/home/${this.username}`;
|
|
1193
|
+
return console.warn(`getUserHomeDirectory: stderr is not empty: ${r}, stdout: ${e}, will get a default home: ${t}`), t;
|
|
1181
1194
|
}
|
|
1182
|
-
return
|
|
1195
|
+
return e.trim();
|
|
1183
1196
|
}
|
|
1184
1197
|
}
|
|
1185
|
-
const
|
|
1198
|
+
const Zt = {
|
|
1186
1199
|
useGlobalAccess: !1,
|
|
1187
1200
|
plBinary: {
|
|
1188
1201
|
type: "Download",
|
|
1189
1202
|
version: R()
|
|
1190
1203
|
}
|
|
1191
1204
|
};
|
|
1205
|
+
async function Yt(n, e) {
|
|
1206
|
+
try {
|
|
1207
|
+
const { stdout: r, stderr: t } = await e.exec("ldd --version | head -n 1");
|
|
1208
|
+
if (t)
|
|
1209
|
+
throw new Error(`Failed to check glibc version: ${t}`);
|
|
1210
|
+
return Qt(r);
|
|
1211
|
+
} catch (r) {
|
|
1212
|
+
throw n.error(`glibc version check failed: ${r}`), r;
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
function Qt(n) {
|
|
1216
|
+
const e = n.match(/\d+\.\d+/);
|
|
1217
|
+
if (!e)
|
|
1218
|
+
throw new Error(`Could not parse glibc version from: ${n}`);
|
|
1219
|
+
return parseFloat(e[0]);
|
|
1220
|
+
}
|
|
1192
1221
|
export {
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1222
|
+
Vt as ConnectionInfo,
|
|
1223
|
+
Dt as LocalConfigYaml,
|
|
1224
|
+
kt as LocalPl,
|
|
1225
|
+
S as PortPair,
|
|
1197
1226
|
B as SshClient,
|
|
1198
|
-
|
|
1199
|
-
|
|
1227
|
+
Z as SshPl,
|
|
1228
|
+
Wt as SshPlPorts,
|
|
1200
1229
|
R as getDefaultPlVersion,
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1230
|
+
gr as localPlatformaInit,
|
|
1231
|
+
qt as newConnectionInfo,
|
|
1232
|
+
zt as parseConnectionInfo,
|
|
1233
|
+
Qt as parseGlibcVersion,
|
|
1234
|
+
Kt as stringifyConnectionInfo
|
|
1205
1235
|
};
|
|
1206
1236
|
//# sourceMappingURL=index.mjs.map
|