@milaboratories/pl-deployments 1.2.3 → 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 +14 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +542 -539
- package/dist/index.mjs.map +1 -1
- package/dist/ssh/pl.d.ts +1 -0
- package/dist/ssh/pl.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/ssh/pl.ts +39 -4
package/dist/index.mjs
CHANGED
|
@@ -1,47 +1,47 @@
|
|
|
1
1
|
var Y = Object.defineProperty;
|
|
2
|
-
var Q = (
|
|
3
|
-
var w = (
|
|
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
4
|
import { spawn as X } from "node:child_process";
|
|
5
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
7
|
import m, { readFile as rt } from "node:fs/promises";
|
|
8
|
-
import
|
|
8
|
+
import u from "upath";
|
|
9
9
|
import { request as et } from "undici";
|
|
10
10
|
import { Readable as it, Writable as ot } from "node:stream";
|
|
11
|
-
import { text as
|
|
12
|
-
import * as
|
|
11
|
+
import { text as nt } from "node:stream/consumers";
|
|
12
|
+
import * as st from "tar";
|
|
13
13
|
import at from "decompress";
|
|
14
14
|
import A from "node:os";
|
|
15
15
|
import ct, { Client as b } from "ssh2";
|
|
16
|
-
import
|
|
16
|
+
import G from "node:net";
|
|
17
17
|
import lt from "node:dns";
|
|
18
|
-
import { randomBytes as
|
|
18
|
+
import { randomBytes as k } from "node:crypto";
|
|
19
19
|
import { generateSshPlConfigs as ht, getFreePort as v } from "@milaboratories/pl-config";
|
|
20
20
|
import { z as p } from "zod";
|
|
21
|
-
function dt(
|
|
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 J(
|
|
37
|
-
let
|
|
38
|
-
for (; await
|
|
39
|
-
if (await F(100),
|
|
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
42
|
const ut = ["linux", "macos", "windows"];
|
|
43
|
-
function O(
|
|
44
|
-
switch (
|
|
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 O(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
57
|
const wt = ["amd64", "arm64"];
|
|
58
|
-
function
|
|
59
|
-
switch (
|
|
58
|
+
function P(n) {
|
|
59
|
+
switch (n) {
|
|
60
60
|
case "aarch64":
|
|
61
61
|
case "aarch64_be":
|
|
62
62
|
case "arm64":
|
|
@@ -66,90 +66,90 @@ 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
73
|
const ft = "https://cdn.platforma.bio/software", pt = "https://cdn-ga.pl-open.science/software";
|
|
74
|
-
async function mt(
|
|
75
|
-
const
|
|
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 gt(
|
|
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 $t(
|
|
90
|
+
return await $t(n, l, h, d), s;
|
|
91
91
|
}
|
|
92
|
-
function L(
|
|
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
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 et(
|
|
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: ${JSON.stringify(i)}, state: ${JSON.stringify(
|
|
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
123
|
const yt = ".ok";
|
|
124
|
-
async function $t(
|
|
125
|
-
if (
|
|
126
|
-
const o = `Platforma Backend binary archive not found at '${
|
|
127
|
-
throw
|
|
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
|
-
await
|
|
141
|
-
file:
|
|
142
|
-
cwd:
|
|
140
|
+
await st.x({
|
|
141
|
+
file: e,
|
|
142
|
+
cwd: t,
|
|
143
143
|
gzip: !0
|
|
144
144
|
});
|
|
145
145
|
break;
|
|
146
146
|
case "zip":
|
|
147
|
-
await at(
|
|
147
|
+
await at(e, t);
|
|
148
148
|
break;
|
|
149
149
|
default:
|
|
150
|
-
H(
|
|
150
|
+
H(r);
|
|
151
151
|
}
|
|
152
|
-
await m.writeFile(i, "ok"),
|
|
152
|
+
await m.writeFile(i, "ok"), n.info(" ... unpack done.");
|
|
153
153
|
}
|
|
154
154
|
const vt = {
|
|
155
155
|
linux: "tgz",
|
|
@@ -159,18 +159,18 @@ const vt = {
|
|
|
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
|
|
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
|
-
H(
|
|
173
|
+
H(r);
|
|
174
174
|
}
|
|
175
175
|
}
|
|
176
176
|
const Ct = {
|
|
@@ -178,59 +178,59 @@ const Ct = {
|
|
|
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 Et(
|
|
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 At(
|
|
191
|
-
await m.writeFile(
|
|
190
|
+
async function At(n, e) {
|
|
191
|
+
await m.writeFile(n, JSON.stringify(e));
|
|
192
192
|
}
|
|
193
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
207
|
const Dt = "config-local.yaml";
|
|
208
|
-
class
|
|
209
|
-
constructor(r, t,
|
|
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
236
|
await J(f(this.pid), 15e3);
|
|
@@ -239,7 +239,7 @@ class xt {
|
|
|
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 xt {
|
|
|
252
252
|
};
|
|
253
253
|
}
|
|
254
254
|
}
|
|
255
|
-
async function gr(
|
|
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 a =
|
|
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
|
|
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,58 +306,58 @@ 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
|
|
355
|
+
return t(`ssh.exec: ${e}: ${i}`);
|
|
356
|
+
let s = "", a = "";
|
|
357
357
|
o.on("close", (c) => {
|
|
358
|
-
c === 0 ?
|
|
358
|
+
c === 0 ? r({ stdout: s, stderr: a }) : t(new Error(`Command ${e} exited with code ${c}, stdout: ${s}, stderr: ${a}`));
|
|
359
359
|
}).on("data", (c) => {
|
|
360
|
-
|
|
360
|
+
s += c.toString();
|
|
361
361
|
}).stderr.on("data", (c) => {
|
|
362
362
|
a += c.toString();
|
|
363
363
|
});
|
|
@@ -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
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,22 +407,22 @@ 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 tt((o) => new Promise((
|
|
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
414
|
const c = new b();
|
|
415
415
|
c.on("ready", () => {
|
|
416
|
-
this.logger.info(`${
|
|
416
|
+
this.logger.info(`${t}.client.ready`), s(c);
|
|
417
417
|
}), c.on("error", (l) => {
|
|
418
|
-
this.logger.info(`${
|
|
418
|
+
this.logger.info(`${t}.client.error: ${l}`), o.reset(), a(l);
|
|
419
419
|
}), c.on("close", () => {
|
|
420
|
-
this.logger.info(`${
|
|
421
|
-
}), c.connect(
|
|
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 a =
|
|
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();
|
|
@@ -431,38 +431,38 @@ class B {
|
|
|
431
431
|
return;
|
|
432
432
|
}
|
|
433
433
|
h.setNoDelay(!0), c.setNoDelay(!0);
|
|
434
|
-
let
|
|
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
438
|
this.logger.error(`${l}.forwardOut.err: ${$}`), c.end();
|
|
439
439
|
return;
|
|
440
440
|
}
|
|
441
|
-
c.pipe(
|
|
442
|
-
this.logger.error(`${l}.stream.error: ${$}`), c.end(),
|
|
443
|
-
}),
|
|
444
|
-
c.end(),
|
|
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
445
|
}), c.on("close", () => {
|
|
446
|
-
this.logger.info(`${l}.localSocket: closed`), c.end(),
|
|
446
|
+
this.logger.info(`${l}.localSocket: closed`), c.end(), d.end();
|
|
447
447
|
});
|
|
448
448
|
});
|
|
449
|
-
a.listen(
|
|
450
|
-
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
451
|
}), a.on("error", (c) => {
|
|
452
|
-
a.close(),
|
|
452
|
+
a.close(), s(new Error(`${t}.server: error: ${JSON.stringify(c)}`));
|
|
453
453
|
}), a.on("close", () => {
|
|
454
|
-
this.logger.info(`${
|
|
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
|
-
lt.lookup(
|
|
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 ct.utils.parseKey(
|
|
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,12 +498,12 @@ 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 (
|
|
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
505
|
const a = new Error(
|
|
506
|
-
`ssh.uploadFile: err: ${
|
|
506
|
+
`ssh.uploadFile: err: ${s}, localPath: ${e}, remotePath: ${r}`
|
|
507
507
|
);
|
|
508
508
|
return o(a);
|
|
509
509
|
}
|
|
@@ -511,143 +511,143 @@ class B {
|
|
|
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(
|
|
532
|
+
e.readdir(r, async (s, a) => {
|
|
533
|
+
if (s)
|
|
534
|
+
return o(s);
|
|
535
535
|
for (const c of a) {
|
|
536
|
-
const l = `${
|
|
536
|
+
const l = `${r}/${c.filename}`;
|
|
537
537
|
if (c.attrs.isDirectory()) {
|
|
538
|
-
|
|
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
583
|
return i(new Error(`ssh.readFile: ${o}`));
|
|
584
|
-
|
|
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
|
-
|
|
615
|
+
async writeFile(e, r, t, i = 432) {
|
|
616
|
+
return new Promise((o, s) => {
|
|
617
|
+
e.writeFile(r, t, { mode: i }, (a) => {
|
|
618
618
|
if (a)
|
|
619
|
-
return
|
|
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
|
-
rt(
|
|
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
629
|
}).catch((c) => {
|
|
630
630
|
const l = `uploadFileUsingExistingSftp: ${c}`;
|
|
631
|
-
this.logger.error(l),
|
|
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(
|
|
636
|
+
async __uploadDirectory(e, r, t, i = 432) {
|
|
637
|
+
return new Promise((o, s) => {
|
|
638
|
+
D.readdir(r, async (a, c) => {
|
|
639
639
|
if (a)
|
|
640
|
-
return
|
|
640
|
+
return s(new Error(`ssh.__uploadDir: err ${a}, localDir: ${r}, remoteDir: ${t}`));
|
|
641
641
|
try {
|
|
642
|
-
await this.__createRemoteDirectory(
|
|
642
|
+
await this.__createRemoteDirectory(e, t);
|
|
643
643
|
for (const l of c) {
|
|
644
|
-
const h =
|
|
645
|
-
D.lstatSync(h).isDirectory() ? await this.__uploadDirectory(
|
|
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,11 +658,11 @@ 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(
|
|
665
|
+
await this.__uploadDirectory(s, e, r, t), i();
|
|
666
666
|
} catch (a) {
|
|
667
667
|
o(new Error(`ssh.uploadDirectory: ${a}`));
|
|
668
668
|
}
|
|
@@ -675,17 +675,17 @@ 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
|
|
678
|
+
__createRemoteDirectory(e, r) {
|
|
679
|
+
return new Promise((t, i) => {
|
|
680
|
+
const o = r.split("/");
|
|
681
|
+
let s = "";
|
|
682
682
|
const a = (c) => {
|
|
683
683
|
if (c >= o.length)
|
|
684
|
-
return
|
|
685
|
-
|
|
686
|
-
l ?
|
|
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: ${
|
|
688
|
+
return i(new Error(`ssh.__createRemDir: err ${h}, remotePath: ${r}`));
|
|
689
689
|
a(c + 1);
|
|
690
690
|
}) : a(c + 1);
|
|
691
691
|
});
|
|
@@ -699,19 +699,19 @@ 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
709
|
await new Promise((a, c) => {
|
|
710
|
-
|
|
710
|
+
t.stat(o, (l) => {
|
|
711
711
|
if (!l) return a();
|
|
712
|
-
|
|
712
|
+
t.mkdir(o, { mode: r }, (h) => {
|
|
713
713
|
if (h)
|
|
714
|
-
return c(new Error(`ssh.createRemoteDir: err ${h}, remotePath: ${
|
|
714
|
+
return c(new Error(`ssh.createRemoteDir: err ${h}, remotePath: ${e}`));
|
|
715
715
|
a();
|
|
716
716
|
});
|
|
717
717
|
});
|
|
@@ -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,92 +744,92 @@ class B {
|
|
|
744
744
|
this.closeForwardedPorts(), this.client.end();
|
|
745
745
|
}
|
|
746
746
|
}
|
|
747
|
-
async function Rt(
|
|
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 Nt(
|
|
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
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(
|
|
764
|
-
return
|
|
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 It(
|
|
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 _t(
|
|
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 jt(
|
|
785
|
-
return
|
|
784
|
+
function jt(n, e) {
|
|
785
|
+
return u.join(q(n, e), "minio");
|
|
786
786
|
}
|
|
787
|
-
function Ht(
|
|
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 K(
|
|
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 Jt(
|
|
809
|
+
async function Jt(n, e, r, t) {
|
|
810
810
|
let i;
|
|
811
811
|
try {
|
|
812
|
-
i = await U(r, t,
|
|
812
|
+
i = await U(e, r, t, "ctl status");
|
|
813
813
|
} catch (c) {
|
|
814
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 a.allAlive || (a.minio ||
|
|
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 Lt(
|
|
827
|
-
const a = Object.entries(
|
|
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}
|
|
@@ -844,68 +844,68 @@ password=${c}
|
|
|
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
853
|
environment=${a}
|
|
854
|
-
command=${o} server ${
|
|
855
|
-
directory=${
|
|
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
|
-
}), Vt = 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 Kt(
|
|
902
|
-
return JSON.stringify(
|
|
901
|
+
function Kt(n) {
|
|
902
|
+
return JSON.stringify(n, void 0, 2);
|
|
903
903
|
}
|
|
904
904
|
const j = 2.28;
|
|
905
905
|
class Z {
|
|
906
|
-
constructor(r, t
|
|
906
|
+
constructor(e, r, t) {
|
|
907
907
|
w(this, "initState", {});
|
|
908
|
-
this.logger =
|
|
908
|
+
this.logger = e, this.sshClient = r, this.username = t;
|
|
909
909
|
}
|
|
910
910
|
info() {
|
|
911
911
|
return {
|
|
@@ -913,12 +913,12 @@ class Z {
|
|
|
913
913
|
initState: this.initState
|
|
914
914
|
};
|
|
915
915
|
}
|
|
916
|
-
static async init(
|
|
916
|
+
static async init(e, r) {
|
|
917
917
|
try {
|
|
918
|
-
const
|
|
919
|
-
return new Z(
|
|
920
|
-
} catch (
|
|
921
|
-
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;
|
|
922
922
|
}
|
|
923
923
|
}
|
|
924
924
|
cleanUp() {
|
|
@@ -926,30 +926,30 @@ class Z {
|
|
|
926
926
|
}
|
|
927
927
|
/** Provides an info if the platforma and minio are running along with the debug info. */
|
|
928
928
|
async isAlive() {
|
|
929
|
-
const
|
|
930
|
-
return await Jt(this.logger, this.sshClient,
|
|
929
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
930
|
+
return await Jt(this.logger, this.sshClient, r, e.arch);
|
|
931
931
|
}
|
|
932
932
|
/** Starts all the services on the server.
|
|
933
933
|
* Idempotent semantic: we could call it several times. */
|
|
934
934
|
async start() {
|
|
935
|
-
const
|
|
935
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
936
936
|
try {
|
|
937
937
|
if (!(await this.isAlive()).allAlive)
|
|
938
|
-
return await
|
|
939
|
-
} catch (
|
|
940
|
-
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}`;
|
|
941
941
|
throw this.logger.error(i), new Error(i);
|
|
942
942
|
}
|
|
943
943
|
}
|
|
944
944
|
/** Stops all the services on the server.
|
|
945
945
|
* Idempotent semantic: we could call it several times. */
|
|
946
946
|
async stop() {
|
|
947
|
-
const
|
|
947
|
+
const e = await this.getArch(), r = await this.getUserHomeDirectory();
|
|
948
948
|
try {
|
|
949
949
|
if ((await this.isAlive()).allAlive)
|
|
950
|
-
return await
|
|
951
|
-
} catch (
|
|
952
|
-
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}`;
|
|
953
953
|
throw this.logger.error(i), new Error(i);
|
|
954
954
|
}
|
|
955
955
|
}
|
|
@@ -959,110 +959,113 @@ class Z {
|
|
|
959
959
|
}
|
|
960
960
|
/** Stops platforma and deletes its state. */
|
|
961
961
|
async stopAndClean() {
|
|
962
|
-
const
|
|
963
|
-
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));
|
|
964
964
|
}
|
|
965
965
|
/** Downloads binaries and untar them on the server,
|
|
966
966
|
* generates all the configs, creates necessary dirs,
|
|
967
967
|
* and finally starts all the services. */
|
|
968
|
-
async platformaInit(
|
|
969
|
-
const
|
|
968
|
+
async platformaInit(e) {
|
|
969
|
+
const r = { localWorkdir: e.localWorkdir }, { onProgress: t } = e;
|
|
970
970
|
try {
|
|
971
|
-
const
|
|
971
|
+
const i = {
|
|
972
972
|
...Zt,
|
|
973
|
-
...
|
|
973
|
+
...e
|
|
974
974
|
};
|
|
975
|
-
if (
|
|
976
|
-
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)
|
|
977
977
|
throw new Error("SshPl.platformaInit: platforma is alive but userCredentials are not found");
|
|
978
|
-
const
|
|
979
|
-
if (
|
|
980
|
-
return t.userCredentials;
|
|
981
|
-
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();
|
|
982
982
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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
|
|
991
992
|
);
|
|
992
|
-
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)
|
|
993
994
|
throw new Error("SshPl.platformaInit: remote ports are not defined");
|
|
994
|
-
|
|
995
|
+
await (t == null ? void 0 : t("Generating server configuration..."));
|
|
996
|
+
const a = await ht({
|
|
995
997
|
logger: this.logger,
|
|
996
|
-
workingDir: g(
|
|
998
|
+
workingDir: g(r.remoteHome),
|
|
997
999
|
portsMode: {
|
|
998
1000
|
type: "customWithMinio",
|
|
999
1001
|
ports: {
|
|
1000
|
-
debug:
|
|
1001
|
-
grpc:
|
|
1002
|
-
minio:
|
|
1003
|
-
minioConsole:
|
|
1004
|
-
monitoring:
|
|
1005
|
-
grpcLocal:
|
|
1006
|
-
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
|
|
1007
1009
|
}
|
|
1008
1010
|
},
|
|
1009
|
-
licenseMode:
|
|
1010
|
-
useGlobalAccess: f(
|
|
1011
|
-
plConfigPostprocessing:
|
|
1011
|
+
licenseMode: i.license,
|
|
1012
|
+
useGlobalAccess: f(i.useGlobalAccess),
|
|
1013
|
+
plConfigPostprocessing: i.plConfigPostprocessing
|
|
1012
1014
|
});
|
|
1013
|
-
|
|
1014
|
-
for (const [
|
|
1015
|
-
await this.sshClient.writeFileOnTheServer(
|
|
1016
|
-
for (const
|
|
1017
|
-
await this.sshClient.ensureRemoteDirCreated(
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
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
|
|
1026
1029
|
);
|
|
1027
|
-
if (!await this.sshClient.writeFileOnTheServer(K(
|
|
1028
|
-
throw new Error(`Can not write supervisord config on the server ${g(
|
|
1029
|
-
return t.connectionInfo =
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
f(
|
|
1034
|
-
|
|
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
|
|
1035
1038
|
), await this.sshClient.writeFileOnTheServer(
|
|
1036
|
-
I(
|
|
1037
|
-
Kt(
|
|
1038
|
-
), await this.start(),
|
|
1039
|
-
} catch (
|
|
1040
|
-
const
|
|
1041
|
-
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);
|
|
1042
1045
|
}
|
|
1043
1046
|
}
|
|
1044
|
-
async downloadBinariesAndUploadToTheServer(r, t,
|
|
1047
|
+
async downloadBinariesAndUploadToTheServer(e, r, t, i) {
|
|
1045
1048
|
const o = [];
|
|
1046
1049
|
try {
|
|
1047
|
-
const
|
|
1048
|
-
r,
|
|
1050
|
+
const s = await this.downloadAndUntar(
|
|
1049
1051
|
e,
|
|
1052
|
+
t,
|
|
1050
1053
|
i,
|
|
1051
1054
|
"pl",
|
|
1052
|
-
`pl-${
|
|
1055
|
+
`pl-${r.version}`
|
|
1053
1056
|
);
|
|
1054
|
-
o.push(
|
|
1057
|
+
o.push(s);
|
|
1055
1058
|
const a = await this.downloadAndUntar(
|
|
1056
|
-
r,
|
|
1057
1059
|
e,
|
|
1060
|
+
t,
|
|
1058
1061
|
i,
|
|
1059
1062
|
"supervisord",
|
|
1060
1063
|
Ut
|
|
1061
1064
|
);
|
|
1062
1065
|
o.push(a);
|
|
1063
|
-
const c = jt(
|
|
1064
|
-
r,
|
|
1066
|
+
const c = jt(t, i.arch), l = await this.downloadAndUntar(
|
|
1065
1067
|
e,
|
|
1068
|
+
t,
|
|
1066
1069
|
i,
|
|
1067
1070
|
"minio",
|
|
1068
1071
|
Bt
|
|
@@ -1070,11 +1073,11 @@ class Z {
|
|
|
1070
1073
|
return o.push(l), await this.sshClient.chmod(c, 488), {
|
|
1071
1074
|
history: o,
|
|
1072
1075
|
minioRelPath: c,
|
|
1073
|
-
downloadedPl: T(
|
|
1076
|
+
downloadedPl: T(t, i.arch)
|
|
1074
1077
|
};
|
|
1075
|
-
} catch (
|
|
1076
|
-
const a = `SshPl.downloadBinariesAndUploadToServer: ${
|
|
1077
|
-
throw this.logger.error(a),
|
|
1078
|
+
} catch (s) {
|
|
1079
|
+
const a = `SshPl.downloadBinariesAndUploadToServer: ${s}, state: ${JSON.stringify(o)}`;
|
|
1080
|
+
throw this.logger.error(a), s;
|
|
1078
1081
|
}
|
|
1079
1082
|
}
|
|
1080
1083
|
/** We have to extract pl in the remote server,
|
|
@@ -1083,113 +1086,113 @@ class Z {
|
|
|
1083
1086
|
* For this reason, we extract all to the remote server.
|
|
1084
1087
|
* It requires `tar` to be installed on the server
|
|
1085
1088
|
* (it's not installed for Rocky Linux for example). */
|
|
1086
|
-
async downloadAndUntar(r, t,
|
|
1087
|
-
const
|
|
1088
|
-
|
|
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;
|
|
1089
1092
|
let a = null;
|
|
1090
1093
|
const c = 5;
|
|
1091
1094
|
for (let h = 1; h <= c; h++)
|
|
1092
1095
|
try {
|
|
1093
1096
|
a = await mt(
|
|
1094
1097
|
this.logger,
|
|
1095
|
-
|
|
1098
|
+
e,
|
|
1096
1099
|
i,
|
|
1097
1100
|
o,
|
|
1098
|
-
|
|
1099
|
-
|
|
1101
|
+
t.arch,
|
|
1102
|
+
t.platform
|
|
1100
1103
|
);
|
|
1101
1104
|
break;
|
|
1102
|
-
} catch (
|
|
1105
|
+
} catch (d) {
|
|
1103
1106
|
if (await F(300), h == c)
|
|
1104
|
-
throw new Error(`downloadAndUntar: ${c} attempts, last error: ${
|
|
1107
|
+
throw new Error(`downloadAndUntar: ${c} attempts, last error: ${d}`);
|
|
1105
1108
|
}
|
|
1106
|
-
|
|
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;
|
|
1107
1110
|
try {
|
|
1108
1111
|
await this.sshClient.exec("hash tar");
|
|
1109
1112
|
} catch {
|
|
1110
1113
|
throw new Error("tar is not installed on the server. Please install it before running Platforma.");
|
|
1111
1114
|
}
|
|
1112
1115
|
const l = await this.sshClient.exec(
|
|
1113
|
-
`tar --warning=no-all -xvf ${
|
|
1116
|
+
`tar --warning=no-all -xvf ${s.remoteArchivePath} --directory=${s.remoteDir}`
|
|
1114
1117
|
);
|
|
1115
1118
|
if (l.stderr)
|
|
1116
1119
|
throw new Error(`downloadAndUntar: untar: stderr occurred: ${l.stderr}, stdout: ${l.stdout}`);
|
|
1117
|
-
return
|
|
1118
|
-
}
|
|
1119
|
-
async needDownload(
|
|
1120
|
-
const
|
|
1121
|
-
return !await this.sshClient.checkFileExists(o) || !await this.sshClient.checkFileExists(i) || !await this.sshClient.checkFileExists(
|
|
1122
|
-
}
|
|
1123
|
-
async checkIsAliveWithInterval(
|
|
1124
|
-
const i =
|
|
1125
|
-
let o = 0,
|
|
1126
|
-
for (;
|
|
1127
|
-
if (await F(
|
|
1128
|
-
throw new Error(`isAliveWithInterval: The process did not ${
|
|
1129
|
-
|
|
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();
|
|
1130
1133
|
}
|
|
1131
1134
|
}
|
|
1132
|
-
async getUserCredentials(
|
|
1133
|
-
const
|
|
1134
|
-
return
|
|
1135
|
+
async getUserCredentials(e) {
|
|
1136
|
+
const r = await this.sshClient.readFile(I(e));
|
|
1137
|
+
return zt(r);
|
|
1135
1138
|
}
|
|
1136
|
-
async fetchPorts(
|
|
1139
|
+
async fetchPorts(e, r) {
|
|
1137
1140
|
return {
|
|
1138
1141
|
grpc: {
|
|
1139
1142
|
local: await v(),
|
|
1140
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1143
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1141
1144
|
},
|
|
1142
1145
|
monitoring: {
|
|
1143
1146
|
local: await v(),
|
|
1144
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1147
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1145
1148
|
},
|
|
1146
1149
|
debug: {
|
|
1147
1150
|
local: await v(),
|
|
1148
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1151
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1149
1152
|
},
|
|
1150
1153
|
minioPort: {
|
|
1151
1154
|
local: await v(),
|
|
1152
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1155
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1153
1156
|
},
|
|
1154
1157
|
minioConsolePort: {
|
|
1155
1158
|
local: await v(),
|
|
1156
|
-
remote: await this.getFreePortForPlatformaOnServer(
|
|
1159
|
+
remote: await this.getFreePortForPlatformaOnServer(e, r)
|
|
1157
1160
|
}
|
|
1158
1161
|
};
|
|
1159
1162
|
}
|
|
1160
1163
|
async getLocalFreePort() {
|
|
1161
|
-
return new Promise((
|
|
1162
|
-
const
|
|
1163
|
-
|
|
1164
|
-
const
|
|
1165
|
-
|
|
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));
|
|
1166
1169
|
});
|
|
1167
1170
|
});
|
|
1168
1171
|
}
|
|
1169
|
-
async getFreePortForPlatformaOnServer(
|
|
1170
|
-
const
|
|
1172
|
+
async getFreePortForPlatformaOnServer(e, r) {
|
|
1173
|
+
const t = _t(e, r.arch), { stdout: i, stderr: o } = await this.sshClient.exec(`${t}`);
|
|
1171
1174
|
if (o)
|
|
1172
1175
|
throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);
|
|
1173
1176
|
return +i;
|
|
1174
1177
|
}
|
|
1175
1178
|
async getArch() {
|
|
1176
|
-
const { stdout:
|
|
1177
|
-
if (
|
|
1178
|
-
throw new Error(`getArch: stderr is not empty: ${
|
|
1179
|
-
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(`
|
|
1180
1183
|
`);
|
|
1181
1184
|
return {
|
|
1182
|
-
platform:
|
|
1183
|
-
arch:
|
|
1185
|
+
platform: t[0],
|
|
1186
|
+
arch: t[1]
|
|
1184
1187
|
};
|
|
1185
1188
|
}
|
|
1186
1189
|
async getUserHomeDirectory() {
|
|
1187
|
-
const { stdout:
|
|
1188
|
-
if (
|
|
1189
|
-
const
|
|
1190
|
-
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;
|
|
1191
1194
|
}
|
|
1192
|
-
return
|
|
1195
|
+
return e.trim();
|
|
1193
1196
|
}
|
|
1194
1197
|
}
|
|
1195
1198
|
const Zt = {
|
|
@@ -1199,34 +1202,34 @@ const Zt = {
|
|
|
1199
1202
|
version: R()
|
|
1200
1203
|
}
|
|
1201
1204
|
};
|
|
1202
|
-
async function Yt(
|
|
1205
|
+
async function Yt(n, e) {
|
|
1203
1206
|
try {
|
|
1204
|
-
const { stdout:
|
|
1205
|
-
if (
|
|
1206
|
-
throw new Error(`Failed to check glibc version: ${
|
|
1207
|
-
return Qt(
|
|
1208
|
-
} catch (
|
|
1209
|
-
throw
|
|
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;
|
|
1210
1213
|
}
|
|
1211
1214
|
}
|
|
1212
|
-
function Qt(
|
|
1213
|
-
const
|
|
1214
|
-
if (!
|
|
1215
|
-
throw new Error(`Could not parse glibc version from: ${
|
|
1216
|
-
return parseFloat(
|
|
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]);
|
|
1217
1220
|
}
|
|
1218
1221
|
export {
|
|
1219
|
-
|
|
1222
|
+
Vt as ConnectionInfo,
|
|
1220
1223
|
Dt as LocalConfigYaml,
|
|
1221
|
-
|
|
1222
|
-
|
|
1224
|
+
kt as LocalPl,
|
|
1225
|
+
S as PortPair,
|
|
1223
1226
|
B as SshClient,
|
|
1224
1227
|
Z as SshPl,
|
|
1225
|
-
|
|
1228
|
+
Wt as SshPlPorts,
|
|
1226
1229
|
R as getDefaultPlVersion,
|
|
1227
1230
|
gr as localPlatformaInit,
|
|
1228
|
-
|
|
1229
|
-
|
|
1231
|
+
qt as newConnectionInfo,
|
|
1232
|
+
zt as parseConnectionInfo,
|
|
1230
1233
|
Qt as parseGlibcVersion,
|
|
1231
1234
|
Kt as stringifyConnectionInfo
|
|
1232
1235
|
};
|