@milaboratories/pl-deployments 1.1.3 → 1.1.5
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 +13 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +470 -392
- 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/dist/ssh/ssh.d.ts +12 -2
- package/dist/ssh/ssh.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/ssh/__tests__/common-utils.ts +1 -1
- package/src/ssh/__tests__/ssh-docker.test.ts +19 -0
- package/src/ssh/pl.ts +17 -6
- package/src/ssh/ssh.ts +198 -56
package/dist/index.mjs
CHANGED
|
@@ -1,45 +1,45 @@
|
|
|
1
|
-
var
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
import { spawn as
|
|
5
|
-
import { sleep as
|
|
1
|
+
var G = Object.defineProperty;
|
|
2
|
+
var Z = (s, r, t) => r in s ? G(s, r, { enumerable: !0, configurable: !0, writable: !0, value: t }) : s[r] = t;
|
|
3
|
+
var w = (s, r, t) => Z(s, typeof r != "symbol" ? r + "" : r, t);
|
|
4
|
+
import { spawn as V } from "node:child_process";
|
|
5
|
+
import { sleep as C, fileExists as m, assertNever as T, notEmpty as f, RetryablePromise as Y } from "@milaboratories/ts-helpers";
|
|
6
6
|
import E from "node:fs";
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import { request as
|
|
10
|
-
import { Readable as
|
|
11
|
-
import { text as
|
|
12
|
-
import * as
|
|
13
|
-
import
|
|
14
|
-
import
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
import
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
function
|
|
7
|
+
import p, { readFile as Q } from "node:fs/promises";
|
|
8
|
+
import u from "upath";
|
|
9
|
+
import { request as X } from "undici";
|
|
10
|
+
import { Readable as tt, Writable as rt } from "node:stream";
|
|
11
|
+
import { text as et } from "node:stream/consumers";
|
|
12
|
+
import * as it from "tar";
|
|
13
|
+
import ot from "decompress";
|
|
14
|
+
import k from "node:os";
|
|
15
|
+
import st, { Client as S } from "ssh2";
|
|
16
|
+
import B from "node:net";
|
|
17
|
+
import nt from "node:dns";
|
|
18
|
+
import { randomBytes as F } from "node:crypto";
|
|
19
|
+
import { generateSshPlConfigs as at, getFreePort as y } from "@milaboratories/pl-config";
|
|
20
|
+
function ct(s, r) {
|
|
21
21
|
return s.info(`Running:
|
|
22
22
|
cmd: ${JSON.stringify([r.cmd, ...r.args])}
|
|
23
|
-
wd: ${r.opts.cwd}`), s.info(" spawning child process"),
|
|
23
|
+
wd: ${r.opts.cwd}`), s.info(" spawning child process"), V(r.cmd, r.args, r.opts);
|
|
24
24
|
}
|
|
25
|
-
async function
|
|
25
|
+
async function D(s) {
|
|
26
26
|
try {
|
|
27
27
|
return process.kill(s, 0), !0;
|
|
28
28
|
} catch {
|
|
29
29
|
return !1;
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
function
|
|
32
|
+
function _(s) {
|
|
33
33
|
return process.kill(s, "SIGINT");
|
|
34
34
|
}
|
|
35
|
-
async function
|
|
35
|
+
async function j(s, r) {
|
|
36
36
|
let e = 0;
|
|
37
|
-
for (; await
|
|
38
|
-
if (await
|
|
37
|
+
for (; await D(s); )
|
|
38
|
+
if (await C(100), e += 100, e > r)
|
|
39
39
|
throw new Error(`The process did not stopped after ${r} ms.`);
|
|
40
40
|
}
|
|
41
|
-
const
|
|
42
|
-
function
|
|
41
|
+
const lt = ["linux", "macos", "windows"];
|
|
42
|
+
function I(s) {
|
|
43
43
|
switch (s.toLowerCase()) {
|
|
44
44
|
case "darwin":
|
|
45
45
|
return "macos";
|
|
@@ -49,12 +49,12 @@ function _(s) {
|
|
|
49
49
|
return "windows";
|
|
50
50
|
default:
|
|
51
51
|
throw new Error(
|
|
52
|
-
`operating system '${s}' is not currently supported by Platforma ecosystem. The list of OSes supported: ` + JSON.stringify(
|
|
52
|
+
`operating system '${s}' is not currently supported by Platforma ecosystem. The list of OSes supported: ` + JSON.stringify(lt)
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
|
-
const
|
|
57
|
-
function
|
|
56
|
+
const ht = ["amd64", "arm64"];
|
|
57
|
+
function P(s) {
|
|
58
58
|
switch (s) {
|
|
59
59
|
case "aarch64":
|
|
60
60
|
case "aarch64_be":
|
|
@@ -65,95 +65,95 @@ function g(s) {
|
|
|
65
65
|
return "amd64";
|
|
66
66
|
default:
|
|
67
67
|
throw new Error(
|
|
68
|
-
`processor architecture '${s}' is not currently supported by Platforma ecosystem. The list of architectures supported: ` + JSON.stringify(
|
|
68
|
+
`processor architecture '${s}' is not currently supported by Platforma ecosystem. The list of architectures supported: ` + JSON.stringify(ht)
|
|
69
69
|
);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
async function
|
|
73
|
-
const n =
|
|
74
|
-
return await H(s,
|
|
72
|
+
async function ut(s, r, t, e, i, o) {
|
|
73
|
+
const n = wt(t, e, r, P(i), I(o)), { archiveUrl: c, archivePath: a } = n;
|
|
74
|
+
return await H(s, c, a), n;
|
|
75
75
|
}
|
|
76
|
-
async function
|
|
77
|
-
const
|
|
78
|
-
return await H(s, n,
|
|
76
|
+
async function dt(s, r, t, e, i) {
|
|
77
|
+
const o = pt(t, r, P(e), I(i)), { archiveUrl: n, archivePath: c, archiveType: a, targetFolder: l, binaryPath: h } = o;
|
|
78
|
+
return await H(s, n, c), await mt(s, c, a, l), o;
|
|
79
79
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
80
|
+
function wt(s, r, t, e, i) {
|
|
81
|
+
const o = `${r}-${e}`, n = M[i], c = `${o}.${n}`, a = `https://cdn.platforma.bio/software/${s}/${i}/${c}`, l = u.join(t, c), h = u.join(t, o);
|
|
82
82
|
return {
|
|
83
|
-
archiveUrl:
|
|
83
|
+
archiveUrl: a,
|
|
84
84
|
archivePath: l,
|
|
85
85
|
archiveType: n,
|
|
86
|
-
targetFolder:
|
|
87
|
-
baseName:
|
|
86
|
+
targetFolder: h,
|
|
87
|
+
baseName: o
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
|
-
function
|
|
91
|
-
const
|
|
90
|
+
function pt(s, r, t, e) {
|
|
91
|
+
const i = `pl-${s}-${t}`, o = M[e], n = `${i}.${o}`, c = `https://cdn.platforma.bio/software/pl/${e}/${n}`, a = u.join(r, n), l = u.join(r, i), h = u.join(i, "binaries", gt[e]);
|
|
92
92
|
return {
|
|
93
|
-
archiveUrl:
|
|
94
|
-
archivePath:
|
|
95
|
-
archiveType:
|
|
93
|
+
archiveUrl: c,
|
|
94
|
+
archivePath: a,
|
|
95
|
+
archiveType: o,
|
|
96
96
|
targetFolder: l,
|
|
97
|
-
binaryPath:
|
|
98
|
-
baseName:
|
|
97
|
+
binaryPath: h,
|
|
98
|
+
baseName: i
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
async function H(s, r, t) {
|
|
102
102
|
const e = {};
|
|
103
103
|
e.dstArchive = t;
|
|
104
104
|
try {
|
|
105
|
-
if (e.fileExisted = await
|
|
105
|
+
if (e.fileExisted = await m(t), e.fileExisted)
|
|
106
106
|
return s.info(`Platforma Backend archive download skipped: '${t}' already exists`), e;
|
|
107
|
-
await
|
|
107
|
+
await p.mkdir(u.dirname(t), { recursive: !0 }), e.dirnameCreated = !0, s.info(`Downloading archive:
|
|
108
108
|
URL: ${r}
|
|
109
109
|
Save to: ${t}`);
|
|
110
|
-
const { body:
|
|
111
|
-
if (e.statusCode =
|
|
112
|
-
const n = await
|
|
113
|
-
throw e.errorMsg = `failed to download archive: ${
|
|
110
|
+
const { body: i, statusCode: o } = await X(r);
|
|
111
|
+
if (e.statusCode = o, o != 200) {
|
|
112
|
+
const n = await et(i);
|
|
113
|
+
throw e.errorMsg = `failed to download archive: ${o}, response: ${n.slice(0, 1e3)}`, s.error(e.errorMsg), new Error(e.errorMsg);
|
|
114
114
|
}
|
|
115
|
-
return e.tmpPath = t + ".tmp", await
|
|
116
|
-
} catch (
|
|
117
|
-
const
|
|
118
|
-
throw s.error(
|
|
115
|
+
return e.tmpPath = t + ".tmp", await tt.toWeb(i).pipeTo(rt.toWeb(E.createWriteStream(e.tmpPath))), e.wroteTmp = !0, e.tmpExisted = await m(e.tmpPath), await p.rename(e.tmpPath, t), e.renamed = !0, e.newExisted = await m(t), e;
|
|
116
|
+
} catch (i) {
|
|
117
|
+
const o = `downloadArchive: error ${JSON.stringify(i)} occurred, state: ${JSON.stringify(e)}`;
|
|
118
|
+
throw s.error(o), new Error(o);
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
const
|
|
122
|
-
async function
|
|
123
|
-
if (s.info("extracting archive..."), s.info(` archive path: '${r}'`), s.info(` target dir: '${e}'`), !await
|
|
124
|
-
const
|
|
125
|
-
throw s.error(
|
|
126
|
-
}
|
|
127
|
-
const
|
|
128
|
-
if (await
|
|
121
|
+
const ft = ".ok";
|
|
122
|
+
async function mt(s, r, t, e) {
|
|
123
|
+
if (s.info("extracting archive..."), s.info(` archive path: '${r}'`), s.info(` target dir: '${e}'`), !await m(r)) {
|
|
124
|
+
const o = `Platforma Backend binary archive not found at '${r}'`;
|
|
125
|
+
throw s.error(o), new Error(o);
|
|
126
|
+
}
|
|
127
|
+
const i = u.join(e, ft);
|
|
128
|
+
if (await m(i)) {
|
|
129
129
|
s.info(`Platforma Backend binaries unpack skipped: '${e}' exists`);
|
|
130
130
|
return;
|
|
131
131
|
}
|
|
132
|
-
switch (await
|
|
132
|
+
switch (await m(e) && (s.info(`Removing previous incompletely unpacked folder: '${e}'`), await p.rm(e, { recursive: !0 })), s.info(` creating target dir '${e}'`), await p.mkdir(e, { recursive: !0 }), s.info(
|
|
133
133
|
`Unpacking Platforma Backend archive:
|
|
134
134
|
Archive: ${r}
|
|
135
135
|
Target dir: ${e}`
|
|
136
136
|
), t) {
|
|
137
137
|
case "tgz":
|
|
138
|
-
await
|
|
138
|
+
await it.x({
|
|
139
139
|
file: r,
|
|
140
140
|
cwd: e,
|
|
141
141
|
gzip: !0
|
|
142
142
|
});
|
|
143
143
|
break;
|
|
144
144
|
case "zip":
|
|
145
|
-
await
|
|
145
|
+
await ot(r, e);
|
|
146
146
|
break;
|
|
147
147
|
default:
|
|
148
|
-
|
|
148
|
+
T(t);
|
|
149
149
|
}
|
|
150
|
-
await
|
|
150
|
+
await p.writeFile(i, "ok"), s.info(" ... unpack done.");
|
|
151
151
|
}
|
|
152
|
-
const
|
|
152
|
+
const M = {
|
|
153
153
|
linux: "tgz",
|
|
154
154
|
macos: "tgz",
|
|
155
155
|
windows: "zip"
|
|
156
|
-
},
|
|
156
|
+
}, gt = {
|
|
157
157
|
linux: "platforma",
|
|
158
158
|
macos: "platforma",
|
|
159
159
|
windows: "platforma.exe"
|
|
@@ -161,81 +161,81 @@ const I = {
|
|
|
161
161
|
function b() {
|
|
162
162
|
return "1.18.3";
|
|
163
163
|
}
|
|
164
|
-
function
|
|
164
|
+
function yt() {
|
|
165
165
|
return { type: "Download", version: b() };
|
|
166
166
|
}
|
|
167
|
-
async function
|
|
167
|
+
async function $t(s, r, t) {
|
|
168
168
|
switch (t.type) {
|
|
169
169
|
case "Download":
|
|
170
|
-
return (await
|
|
170
|
+
return (await dt(s, r, t.version, k.arch(), k.platform())).binaryPath;
|
|
171
171
|
case "Local":
|
|
172
172
|
return t.path;
|
|
173
173
|
default:
|
|
174
|
-
|
|
174
|
+
T(t);
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
|
-
function
|
|
178
|
-
return
|
|
177
|
+
function J(s) {
|
|
178
|
+
return u.join(s, "pl_pid");
|
|
179
179
|
}
|
|
180
|
-
async function
|
|
181
|
-
if (!await
|
|
180
|
+
async function Pt(s) {
|
|
181
|
+
if (!await m(s))
|
|
182
182
|
return;
|
|
183
|
-
const r = await
|
|
183
|
+
const r = await p.readFile(s);
|
|
184
184
|
return Number(r.toString());
|
|
185
185
|
}
|
|
186
|
-
async function
|
|
187
|
-
await
|
|
186
|
+
async function vt(s, r) {
|
|
187
|
+
await p.writeFile(s, JSON.stringify(r));
|
|
188
188
|
}
|
|
189
|
-
function
|
|
189
|
+
function St() {
|
|
190
190
|
return {};
|
|
191
191
|
}
|
|
192
|
-
function
|
|
192
|
+
function Ct(s, r, t) {
|
|
193
193
|
return s[r] = t, t;
|
|
194
194
|
}
|
|
195
195
|
async function A(s, r) {
|
|
196
|
-
const t =
|
|
196
|
+
const t = St();
|
|
197
197
|
try {
|
|
198
|
-
return await r((
|
|
198
|
+
return await r((i, o) => Ct(t, i, o), t);
|
|
199
199
|
} catch (e) {
|
|
200
200
|
throw s.error(`error ${e} while doing traced operation, state: ${JSON.stringify(t)}`), e;
|
|
201
201
|
}
|
|
202
202
|
}
|
|
203
|
-
const
|
|
204
|
-
class
|
|
205
|
-
constructor(r, t, e,
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
this.logger = r, this.workingDir = t, this.startOptions = e, this.initialStartHistory =
|
|
203
|
+
const Et = "config-local.yaml";
|
|
204
|
+
class Ft {
|
|
205
|
+
constructor(r, t, e, i, o, n, c, a) {
|
|
206
|
+
w(this, "instance");
|
|
207
|
+
w(this, "pid");
|
|
208
|
+
w(this, "nRuns", 0);
|
|
209
|
+
w(this, "lastRunHistory", {});
|
|
210
|
+
w(this, "wasStopped", !1);
|
|
211
|
+
this.logger = r, this.workingDir = t, this.startOptions = e, this.initialStartHistory = i, this.onClose = o, this.onError = n, this.onCloseAndError = c, this.onCloseAndErrorNoStop = a;
|
|
212
212
|
}
|
|
213
213
|
async start() {
|
|
214
214
|
await A(this.logger, async (r, t) => {
|
|
215
215
|
this.wasStopped = !1;
|
|
216
|
-
const e =
|
|
217
|
-
e.on("error", (
|
|
216
|
+
const e = ct(this.logger, this.startOptions);
|
|
217
|
+
e.on("error", (o) => {
|
|
218
218
|
this.logger.error(
|
|
219
|
-
`error '${
|
|
219
|
+
`error '${o}', while running platforma, started opts: ${JSON.stringify(this.debugInfo())}`
|
|
220
220
|
), this.onError !== void 0 && this.onError(this), this.onCloseAndError !== void 0 && this.onCloseAndError(this), this.onCloseAndErrorNoStop !== void 0 && !this.wasStopped && this.onCloseAndErrorNoStop(this);
|
|
221
221
|
}), e.on("close", () => {
|
|
222
222
|
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);
|
|
223
223
|
}), r("started", !0);
|
|
224
|
-
const
|
|
225
|
-
r("pid",
|
|
224
|
+
const i = r("pidFile", J(this.workingDir));
|
|
225
|
+
r("pid", f(e.pid)), r("pidWritten", await vt(i, f(e.pid))), this.nRuns++, this.instance = e, this.pid = e.pid, this.lastRunHistory = t;
|
|
226
226
|
});
|
|
227
227
|
}
|
|
228
228
|
stop() {
|
|
229
|
-
this.wasStopped = !0,
|
|
229
|
+
this.wasStopped = !0, _(f(this.pid));
|
|
230
230
|
}
|
|
231
231
|
async waitStopped() {
|
|
232
|
-
await
|
|
232
|
+
await j(f(this.pid), 15e3);
|
|
233
233
|
}
|
|
234
234
|
stopped() {
|
|
235
235
|
return this.wasStopped;
|
|
236
236
|
}
|
|
237
237
|
async isAlive() {
|
|
238
|
-
return await
|
|
238
|
+
return await D(f(this.pid));
|
|
239
239
|
}
|
|
240
240
|
debugInfo() {
|
|
241
241
|
return {
|
|
@@ -248,25 +248,25 @@ class Et {
|
|
|
248
248
|
};
|
|
249
249
|
}
|
|
250
250
|
}
|
|
251
|
-
async function
|
|
251
|
+
async function ir(s, r) {
|
|
252
252
|
const t = {
|
|
253
|
-
plBinary:
|
|
253
|
+
plBinary: yt(),
|
|
254
254
|
spawnOptions: {},
|
|
255
255
|
closeOld: !0,
|
|
256
256
|
...r
|
|
257
257
|
};
|
|
258
|
-
return await A(s, async (e,
|
|
258
|
+
return await A(s, async (e, i) => {
|
|
259
259
|
e("startOptions", { ...t, config: "too wordy" });
|
|
260
|
-
const
|
|
261
|
-
t.closeOld && e("closeOld", await
|
|
262
|
-
const n =
|
|
263
|
-
s.info(`writing configuration '${n}'...`), await
|
|
264
|
-
const
|
|
265
|
-
cmd: e("binaryPath",
|
|
260
|
+
const o = u.resolve(t.workingDir);
|
|
261
|
+
t.closeOld && e("closeOld", await Dt(s, o));
|
|
262
|
+
const n = u.join(o, Et);
|
|
263
|
+
s.info(`writing configuration '${n}'...`), await p.writeFile(n, t.config);
|
|
264
|
+
const c = await $t(s, u.join(o, "binaries"), t.plBinary), l = {
|
|
265
|
+
cmd: e("binaryPath", u.join("binaries", c)),
|
|
266
266
|
args: ["-config", n],
|
|
267
267
|
opts: {
|
|
268
268
|
env: { ...process.env },
|
|
269
|
-
cwd:
|
|
269
|
+
cwd: o,
|
|
270
270
|
stdio: ["pipe", "ignore", "inherit"],
|
|
271
271
|
windowsHide: !0,
|
|
272
272
|
// hide a terminal on Windows
|
|
@@ -278,33 +278,33 @@ async function Xt(s, r) {
|
|
|
278
278
|
args: l.args,
|
|
279
279
|
cwd: l.opts.cwd
|
|
280
280
|
});
|
|
281
|
-
const
|
|
281
|
+
const h = new Ft(
|
|
282
282
|
s,
|
|
283
283
|
t.workingDir,
|
|
284
284
|
l,
|
|
285
|
-
|
|
285
|
+
i,
|
|
286
286
|
t.onClose,
|
|
287
287
|
t.onError,
|
|
288
288
|
t.onCloseAndError,
|
|
289
289
|
t.onCloseAndErrorNoStop
|
|
290
290
|
);
|
|
291
|
-
return await
|
|
291
|
+
return await h.start(), h;
|
|
292
292
|
});
|
|
293
293
|
}
|
|
294
|
-
async function
|
|
294
|
+
async function Dt(s, r) {
|
|
295
295
|
return await A(s, async (t, e) => {
|
|
296
|
-
const
|
|
297
|
-
return
|
|
296
|
+
const i = t("pidFilePath", J(r)), o = t("pid", await Pt(i)), n = t("wasAlive", await D(o));
|
|
297
|
+
return o !== void 0 && n && (t("stopped", _(o)), t("waitStopped", await j(o, 1e4))), e;
|
|
298
298
|
});
|
|
299
299
|
}
|
|
300
300
|
const bt = {
|
|
301
301
|
keepaliveInterval: 6e4,
|
|
302
302
|
keepaliveCountMax: 10
|
|
303
303
|
};
|
|
304
|
-
class
|
|
304
|
+
class x {
|
|
305
305
|
constructor(r, t) {
|
|
306
|
-
|
|
307
|
-
|
|
306
|
+
w(this, "config");
|
|
307
|
+
w(this, "homeDir");
|
|
308
308
|
this.logger = r, this.client = t;
|
|
309
309
|
}
|
|
310
310
|
/**
|
|
@@ -316,8 +316,16 @@ class D {
|
|
|
316
316
|
const e = {
|
|
317
317
|
...bt,
|
|
318
318
|
...t
|
|
319
|
-
},
|
|
320
|
-
return await
|
|
319
|
+
}, i = new x(r, new S());
|
|
320
|
+
return await i.connect(e), i;
|
|
321
|
+
}
|
|
322
|
+
getFullHostName() {
|
|
323
|
+
var r, t;
|
|
324
|
+
return `${(r = this.config) == null ? void 0 : r.host}:${(t = this.config) == null ? void 0 : t.port}`;
|
|
325
|
+
}
|
|
326
|
+
getUserName() {
|
|
327
|
+
var r;
|
|
328
|
+
return (r = this.config) == null ? void 0 : r.username;
|
|
321
329
|
}
|
|
322
330
|
/**
|
|
323
331
|
* Connects to the SSH server using the specified configuration.
|
|
@@ -325,15 +333,7 @@ class D {
|
|
|
325
333
|
* @returns A promise that resolves when the connection is established or rejects on error.
|
|
326
334
|
*/
|
|
327
335
|
async connect(r) {
|
|
328
|
-
return this.config = r,
|
|
329
|
-
this.client.on("ready", () => {
|
|
330
|
-
t(void 0);
|
|
331
|
-
}).on("error", (o) => {
|
|
332
|
-
e(new Error(`ssh.connect: error occurred: ${o}`));
|
|
333
|
-
}).on("timeout", () => {
|
|
334
|
-
e(new Error("timeout was occurred while waiting for SSH connection."));
|
|
335
|
-
}).connect(r);
|
|
336
|
-
});
|
|
336
|
+
return this.config = r, await At(this.client, r);
|
|
337
337
|
}
|
|
338
338
|
/**
|
|
339
339
|
* Executes a command on the SSH server.
|
|
@@ -342,16 +342,16 @@ class D {
|
|
|
342
342
|
*/
|
|
343
343
|
async exec(r) {
|
|
344
344
|
return new Promise((t, e) => {
|
|
345
|
-
this.client.exec(r, (
|
|
346
|
-
if (
|
|
347
|
-
return e(`ssh.exec: ${r}, error occurred: ${
|
|
348
|
-
let n = "",
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
}).on("data", (
|
|
352
|
-
n +=
|
|
353
|
-
}).stderr.on("data", (
|
|
354
|
-
|
|
345
|
+
this.client.exec(r, (i, o) => {
|
|
346
|
+
if (i)
|
|
347
|
+
return e(`ssh.exec: ${r}, error occurred: ${i}`);
|
|
348
|
+
let n = "", c = "";
|
|
349
|
+
o.on("close", (a) => {
|
|
350
|
+
a === 0 ? t({ stdout: n, stderr: c }) : e(new Error(`Command ${r} exited with code ${a}`));
|
|
351
|
+
}).on("data", (a) => {
|
|
352
|
+
n += a.toString();
|
|
353
|
+
}).stderr.on("data", (a) => {
|
|
354
|
+
c += a.toString();
|
|
355
355
|
});
|
|
356
356
|
});
|
|
357
357
|
});
|
|
@@ -364,20 +364,20 @@ class D {
|
|
|
364
364
|
*/
|
|
365
365
|
static async getAuthTypes(r, t) {
|
|
366
366
|
return new Promise((e) => {
|
|
367
|
-
let
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
const n = this.extractAuthMethods(
|
|
367
|
+
let i = "";
|
|
368
|
+
const o = new S();
|
|
369
|
+
o.on("ready", () => {
|
|
370
|
+
o.end();
|
|
371
|
+
const n = this.extractAuthMethods(i);
|
|
372
372
|
e(n.length === 0 ? ["publickey", "password"] : n);
|
|
373
|
-
}),
|
|
374
|
-
|
|
375
|
-
}),
|
|
373
|
+
}), o.on("error", () => {
|
|
374
|
+
o.end(), e(["publickey", "password"]);
|
|
375
|
+
}), o.connect({
|
|
376
376
|
host: r,
|
|
377
377
|
port: t,
|
|
378
378
|
username: (/* @__PURE__ */ new Date()).getTime().toString(),
|
|
379
379
|
debug: (n) => {
|
|
380
|
-
|
|
380
|
+
i += `${n}
|
|
381
381
|
`;
|
|
382
382
|
}
|
|
383
383
|
});
|
|
@@ -400,40 +400,50 @@ class D {
|
|
|
400
400
|
* @returns { server: net.Server } A promise resolving with the created server instance.
|
|
401
401
|
*/
|
|
402
402
|
async forwardPort(r, t) {
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
403
|
+
const e = `ssh.forward:${r.localPort}:${r.remotePort}.id_${F(1).toString("hex")}`;
|
|
404
|
+
t = t ?? this.config;
|
|
405
|
+
const i = new Y((o) => new Promise((n, c) => {
|
|
406
|
+
const a = new S();
|
|
407
|
+
a.on("ready", () => {
|
|
408
|
+
this.logger.info(`${e}.client.ready`), n(a);
|
|
409
|
+
}), a.on("error", (l) => {
|
|
410
|
+
this.logger.info(`${e}.client.error: ${l}`), o.reset(), c(l);
|
|
411
|
+
}), a.on("close", () => {
|
|
412
|
+
this.logger.info(`${e}.client.closed`), o.reset();
|
|
413
|
+
}), a.connect(t);
|
|
414
|
+
}));
|
|
415
|
+
return await i.ensure(), new Promise((o, n) => {
|
|
416
|
+
const c = B.createServer({ pauseOnConnect: !0 }, async (a) => {
|
|
417
|
+
const l = `${e}.sock_${F(1).toString("hex")}`;
|
|
418
|
+
let h;
|
|
419
|
+
try {
|
|
420
|
+
h = await i.ensure();
|
|
421
|
+
} catch (g) {
|
|
422
|
+
this.logger.info(`${l}.persistentClient.catch: ${g}`), a.end();
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
let d;
|
|
426
|
+
try {
|
|
427
|
+
d = await xt(this.logger, h, "127.0.0.1", 0, "127.0.0.1", r.remotePort);
|
|
428
|
+
} catch (g) {
|
|
429
|
+
this.logger.error(`${l}.forwardOut.err: ${g}`), a.end();
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
a.pipe(d), d.pipe(a), a.resume(), d.on("error", (g) => {
|
|
433
|
+
this.logger.error(`${l}.stream.error: ${g}`), a.end(), d.end();
|
|
434
|
+
}), d.on("close", () => {
|
|
435
|
+
a.end(), d.end();
|
|
436
|
+
}), a.on("close", () => {
|
|
437
|
+
this.logger.info(`${l}.localSocket: closed`), a.end(), d.end();
|
|
431
438
|
});
|
|
432
|
-
})
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
439
|
+
});
|
|
440
|
+
c.listen(r.localPort, "127.0.0.1", () => {
|
|
441
|
+
this.logger.info(`${e}.server: started listening`), o({ server: c });
|
|
442
|
+
}), c.on("error", (a) => {
|
|
443
|
+
c.close(), n(new Error(`${e}.server: error: ${JSON.stringify(a)}`));
|
|
444
|
+
}), c.on("close", () => {
|
|
445
|
+
this.logger.info(`${e}.server: closed ${JSON.stringify(r)}`);
|
|
446
|
+
});
|
|
437
447
|
});
|
|
438
448
|
}
|
|
439
449
|
/**
|
|
@@ -443,7 +453,7 @@ class D {
|
|
|
443
453
|
*/
|
|
444
454
|
static async checkHostAvailability(r) {
|
|
445
455
|
return new Promise((t) => {
|
|
446
|
-
|
|
456
|
+
nt.lookup(r, (e) => {
|
|
447
457
|
t(!e);
|
|
448
458
|
});
|
|
449
459
|
});
|
|
@@ -456,9 +466,9 @@ class D {
|
|
|
456
466
|
static async isPassphraseRequiredForKey(r) {
|
|
457
467
|
return new Promise((t, e) => {
|
|
458
468
|
try {
|
|
459
|
-
return
|
|
460
|
-
} catch (
|
|
461
|
-
console.log("Error parsing privateKey"), e(new Error(`ssh.isPassphraseRequiredForKey: err ${
|
|
469
|
+
return st.utils.parseKey(r) instanceof Error && t(!0), t(!1);
|
|
470
|
+
} catch (i) {
|
|
471
|
+
console.log("Error parsing privateKey"), e(new Error(`ssh.isPassphraseRequiredForKey: err ${i}`));
|
|
462
472
|
}
|
|
463
473
|
});
|
|
464
474
|
}
|
|
@@ -470,15 +480,15 @@ class D {
|
|
|
470
480
|
* @returns A promise resolving with `true` if the file was successfully uploaded.
|
|
471
481
|
*/
|
|
472
482
|
async uploadFile(r, t) {
|
|
473
|
-
return await this.withSftp(async (e) => new Promise((
|
|
483
|
+
return await this.withSftp(async (e) => new Promise((i, o) => {
|
|
474
484
|
e.fastPut(r, t, (n) => {
|
|
475
485
|
if (n) {
|
|
476
|
-
const
|
|
486
|
+
const c = new Error(
|
|
477
487
|
`ssh.uploadFile: err: ${n}, localPath: ${r}, remotePath: ${t}`
|
|
478
488
|
);
|
|
479
|
-
return
|
|
489
|
+
return o(c);
|
|
480
490
|
}
|
|
481
|
-
|
|
491
|
+
i(!0);
|
|
482
492
|
});
|
|
483
493
|
}));
|
|
484
494
|
}
|
|
@@ -489,48 +499,97 @@ class D {
|
|
|
489
499
|
}
|
|
490
500
|
async withSftp(r) {
|
|
491
501
|
return new Promise((t, e) => {
|
|
492
|
-
this.client.sftp((
|
|
493
|
-
if (
|
|
494
|
-
return e(new Error(`ssh.withSftp: sftp err: ${
|
|
495
|
-
r(
|
|
502
|
+
this.client.sftp((i, o) => {
|
|
503
|
+
if (i)
|
|
504
|
+
return e(new Error(`ssh.withSftp: sftp err: ${i}`));
|
|
505
|
+
r(o).then(t).catch((n) => {
|
|
496
506
|
e(new Error(`ssh.withSftp.callback: err ${n}`));
|
|
497
507
|
}).finally(() => {
|
|
498
|
-
|
|
508
|
+
o == null || o.end();
|
|
499
509
|
});
|
|
500
510
|
});
|
|
501
511
|
});
|
|
502
512
|
}
|
|
503
513
|
async writeFileOnTheServer(r, t, e = 432) {
|
|
504
|
-
return this.withSftp(async (
|
|
514
|
+
return this.withSftp(async (i) => this.writeFile(i, r, t, e));
|
|
515
|
+
}
|
|
516
|
+
async getForderStructure(r, t, e = { files: [], directories: [] }) {
|
|
517
|
+
return new Promise((i, o) => {
|
|
518
|
+
r.readdir(t, async (n, c) => {
|
|
519
|
+
if (n)
|
|
520
|
+
return o(n);
|
|
521
|
+
for (const a of c) {
|
|
522
|
+
const l = `${t}/${a.filename}`;
|
|
523
|
+
if (a.attrs.isDirectory()) {
|
|
524
|
+
e.directories.push(l);
|
|
525
|
+
try {
|
|
526
|
+
await this.getForderStructure(r, l, e);
|
|
527
|
+
} catch (h) {
|
|
528
|
+
return o(h);
|
|
529
|
+
}
|
|
530
|
+
} else
|
|
531
|
+
e.files.push(l);
|
|
532
|
+
}
|
|
533
|
+
i(e);
|
|
534
|
+
});
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
rmdir(r, t) {
|
|
538
|
+
return new Promise((e, i) => {
|
|
539
|
+
r.rmdir(t, (o) => o ? i(o) : e(!0));
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
unlink(r, t) {
|
|
543
|
+
return new Promise((e, i) => {
|
|
544
|
+
r.unlink(t, (o) => o ? i(o) : e(!0));
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
async deleteFolder(r) {
|
|
548
|
+
return this.withSftp(async (t) => {
|
|
549
|
+
try {
|
|
550
|
+
const e = await this.getForderStructure(t, r);
|
|
551
|
+
this.logger.info("ssh.deleteFolder list of files and directories"), this.logger.info(`ssh.deleteFolder list of files: ${e.files}`), this.logger.info(`ssh.deleteFolder list of directories: ${e.directories}`);
|
|
552
|
+
for (const i of e.files)
|
|
553
|
+
this.logger.info(`ssh.deleteFolder unlink file ${i}`), await this.unlink(t, i);
|
|
554
|
+
e.directories.sort((i, o) => o.length - i.length);
|
|
555
|
+
for (const i of e.directories)
|
|
556
|
+
this.logger.info(`ssh.deleteFolder rmdir ${i}`), await this.rmdir(t, i);
|
|
557
|
+
return await this.rmdir(t, r), !0;
|
|
558
|
+
} catch (e) {
|
|
559
|
+
this.logger.error(e);
|
|
560
|
+
const i = e instanceof Error ? e.message : "";
|
|
561
|
+
throw new Error(`ssh.deleteFolder: path: ${r}, message: ${i}`);
|
|
562
|
+
}
|
|
563
|
+
});
|
|
505
564
|
}
|
|
506
565
|
async readFile(r) {
|
|
507
|
-
return this.withSftp(async (t) => new Promise((e,
|
|
508
|
-
t.readFile(r, (
|
|
509
|
-
if (
|
|
510
|
-
return
|
|
566
|
+
return this.withSftp(async (t) => new Promise((e, i) => {
|
|
567
|
+
t.readFile(r, (o, n) => {
|
|
568
|
+
if (o)
|
|
569
|
+
return i(new Error(`ssh.readFile: err occurred ${o}`));
|
|
511
570
|
e(n.toString());
|
|
512
571
|
});
|
|
513
572
|
}));
|
|
514
573
|
}
|
|
515
574
|
async chmod(r, t) {
|
|
516
|
-
return this.withSftp(async (e) => new Promise((
|
|
517
|
-
e.chmod(r, t, (n) => n ?
|
|
575
|
+
return this.withSftp(async (e) => new Promise((i, o) => {
|
|
576
|
+
e.chmod(r, t, (n) => n ? o(new Error(`ssh.chmod: ${n}, path: ${r}, mode: ${t}`)) : i(void 0));
|
|
518
577
|
}));
|
|
519
578
|
}
|
|
520
579
|
async checkFileExists(r) {
|
|
521
|
-
return this.withSftp(async (t) => new Promise((e,
|
|
522
|
-
t.stat(r, (
|
|
523
|
-
if (
|
|
524
|
-
return
|
|
580
|
+
return this.withSftp(async (t) => new Promise((e, i) => {
|
|
581
|
+
t.stat(r, (o, n) => {
|
|
582
|
+
if (o)
|
|
583
|
+
return o.code === 2 ? e(!1) : i(new Error(`ssh.checkFileExists: err ${o}`));
|
|
525
584
|
e(n.isFile());
|
|
526
585
|
});
|
|
527
586
|
}));
|
|
528
587
|
}
|
|
529
588
|
async checkPathExists(r) {
|
|
530
|
-
return this.withSftp(async (t) => new Promise((e,
|
|
531
|
-
t.stat(r, (
|
|
532
|
-
if (
|
|
533
|
-
return
|
|
589
|
+
return this.withSftp(async (t) => new Promise((e, i) => {
|
|
590
|
+
t.stat(r, (o, n) => {
|
|
591
|
+
if (o)
|
|
592
|
+
return o.code === 2 ? e({ exists: !1, isFile: !1, isDirectory: !1 }) : i(new Error(`ssh.checkPathExists: ${o}`));
|
|
534
593
|
e({
|
|
535
594
|
exists: !0,
|
|
536
595
|
isFile: n.isFile(),
|
|
@@ -539,42 +598,42 @@ class D {
|
|
|
539
598
|
});
|
|
540
599
|
}));
|
|
541
600
|
}
|
|
542
|
-
async writeFile(r, t, e,
|
|
543
|
-
return new Promise((
|
|
544
|
-
r.writeFile(t, e, { mode:
|
|
545
|
-
if (
|
|
546
|
-
return n(new Error(`ssh.writeFile: err ${
|
|
547
|
-
|
|
601
|
+
async writeFile(r, t, e, i = 432) {
|
|
602
|
+
return new Promise((o, n) => {
|
|
603
|
+
r.writeFile(t, e, { mode: i }, (c) => {
|
|
604
|
+
if (c)
|
|
605
|
+
return n(new Error(`ssh.writeFile: err ${c}, remotePath: ${t}`));
|
|
606
|
+
o(!0);
|
|
548
607
|
});
|
|
549
608
|
});
|
|
550
609
|
}
|
|
551
|
-
uploadFileUsingExistingSftp(r, t, e,
|
|
552
|
-
return new Promise((
|
|
553
|
-
|
|
554
|
-
this.writeFile(r, e,
|
|
555
|
-
|
|
556
|
-
}).catch((
|
|
557
|
-
const l = `uploadFileUsingExistingSftp: error ${
|
|
610
|
+
uploadFileUsingExistingSftp(r, t, e, i = 432) {
|
|
611
|
+
return new Promise((o, n) => {
|
|
612
|
+
Q(t).then(async (c) => {
|
|
613
|
+
this.writeFile(r, e, c, i).then(() => {
|
|
614
|
+
o(void 0);
|
|
615
|
+
}).catch((a) => {
|
|
616
|
+
const l = `uploadFileUsingExistingSftp: error ${a} occurred`;
|
|
558
617
|
this.logger.error(l), n(new Error(l));
|
|
559
618
|
});
|
|
560
619
|
});
|
|
561
620
|
});
|
|
562
621
|
}
|
|
563
|
-
async __uploadDirectory(r, t, e,
|
|
564
|
-
return new Promise((
|
|
565
|
-
E.readdir(t, async (
|
|
566
|
-
if (
|
|
567
|
-
return n(new Error(`ssh.__uploadDir: err ${
|
|
622
|
+
async __uploadDirectory(r, t, e, i = 432) {
|
|
623
|
+
return new Promise((o, n) => {
|
|
624
|
+
E.readdir(t, async (c, a) => {
|
|
625
|
+
if (c)
|
|
626
|
+
return n(new Error(`ssh.__uploadDir: err ${c}, localDir: ${t}, remoteDir: ${e}`));
|
|
568
627
|
try {
|
|
569
628
|
await this.__createRemoteDirectory(r, e);
|
|
570
|
-
for (const l of
|
|
571
|
-
const
|
|
572
|
-
E.lstatSync(
|
|
629
|
+
for (const l of a) {
|
|
630
|
+
const h = u.join(t, l), d = `${e}/${l}`;
|
|
631
|
+
E.lstatSync(h).isDirectory() ? await this.__uploadDirectory(r, h, d, i) : await this.uploadFileUsingExistingSftp(r, h, d, i);
|
|
573
632
|
}
|
|
574
|
-
|
|
633
|
+
o();
|
|
575
634
|
} catch (l) {
|
|
576
|
-
const
|
|
577
|
-
this.logger.error(
|
|
635
|
+
const h = `ssh.__uploadDir: catched err ${l}`;
|
|
636
|
+
this.logger.error(h), n(new Error(h));
|
|
578
637
|
}
|
|
579
638
|
});
|
|
580
639
|
});
|
|
@@ -586,9 +645,9 @@ class D {
|
|
|
586
645
|
* @returns A promise that resolves when the directory and its contents are uploaded.
|
|
587
646
|
*/
|
|
588
647
|
async uploadDirectory(r, t, e = 432) {
|
|
589
|
-
return new Promise((
|
|
648
|
+
return new Promise((i, o) => {
|
|
590
649
|
this.withSftp(async (n) => {
|
|
591
|
-
await this.__uploadDirectory(n, r, t, e),
|
|
650
|
+
await this.__uploadDirectory(n, r, t, e), i();
|
|
592
651
|
});
|
|
593
652
|
});
|
|
594
653
|
}
|
|
@@ -599,21 +658,21 @@ class D {
|
|
|
599
658
|
* @returns A promise that resolves when the directory is created.
|
|
600
659
|
*/
|
|
601
660
|
__createRemoteDirectory(r, t) {
|
|
602
|
-
return new Promise((e,
|
|
603
|
-
const
|
|
661
|
+
return new Promise((e, i) => {
|
|
662
|
+
const o = t.split("/");
|
|
604
663
|
let n = "";
|
|
605
|
-
const
|
|
606
|
-
if (
|
|
664
|
+
const c = (a) => {
|
|
665
|
+
if (a >= o.length)
|
|
607
666
|
return e();
|
|
608
|
-
n += `${
|
|
609
|
-
l ? r.mkdir(n, (
|
|
610
|
-
if (
|
|
611
|
-
return
|
|
612
|
-
a
|
|
613
|
-
}) : a
|
|
667
|
+
n += `${o[a]}/`, r.stat(n, (l) => {
|
|
668
|
+
l ? r.mkdir(n, (h) => {
|
|
669
|
+
if (h)
|
|
670
|
+
return i(new Error(`ssh.__createRemDir: err ${h}, remotePath: ${t}`));
|
|
671
|
+
c(a + 1);
|
|
672
|
+
}) : c(a + 1);
|
|
614
673
|
});
|
|
615
674
|
};
|
|
616
|
-
|
|
675
|
+
c(0);
|
|
617
676
|
});
|
|
618
677
|
}
|
|
619
678
|
/**
|
|
@@ -624,23 +683,23 @@ class D {
|
|
|
624
683
|
*/
|
|
625
684
|
createRemoteDirectory(r, t = 493) {
|
|
626
685
|
return this.withSftp(async (e) => {
|
|
627
|
-
const
|
|
628
|
-
let
|
|
629
|
-
for (const n of
|
|
630
|
-
|
|
686
|
+
const i = r.split("/");
|
|
687
|
+
let o = "";
|
|
688
|
+
for (const n of i) {
|
|
689
|
+
o += `${n}/`;
|
|
631
690
|
try {
|
|
632
|
-
await new Promise((
|
|
633
|
-
e.stat(
|
|
634
|
-
if (!l) return
|
|
635
|
-
e.mkdir(
|
|
636
|
-
if (
|
|
637
|
-
return
|
|
638
|
-
|
|
691
|
+
await new Promise((c, a) => {
|
|
692
|
+
e.stat(o, (l) => {
|
|
693
|
+
if (!l) return c();
|
|
694
|
+
e.mkdir(o, { mode: t }, (h) => {
|
|
695
|
+
if (h)
|
|
696
|
+
return a(new Error(`ssh.createRemoteDir: err ${h}, remotePath: ${r}`));
|
|
697
|
+
c();
|
|
639
698
|
});
|
|
640
699
|
});
|
|
641
700
|
});
|
|
642
|
-
} catch (
|
|
643
|
-
throw console.error(`Failed to create directory: ${
|
|
701
|
+
} catch (c) {
|
|
702
|
+
throw console.error(`Failed to create directory: ${o}`, c), c;
|
|
644
703
|
}
|
|
645
704
|
}
|
|
646
705
|
});
|
|
@@ -652,11 +711,11 @@ class D {
|
|
|
652
711
|
* @returns A promise resolving with `true` if the file was successfully downloaded.
|
|
653
712
|
*/
|
|
654
713
|
async downloadFile(r, t) {
|
|
655
|
-
return this.withSftp(async (e) => new Promise((
|
|
714
|
+
return this.withSftp(async (e) => new Promise((i, o) => {
|
|
656
715
|
e.fastGet(r, t, (n) => {
|
|
657
716
|
if (n)
|
|
658
|
-
return
|
|
659
|
-
|
|
717
|
+
return o(new Error(`ssh.downloadFile: err ${n}, remotePath: ${r}, localPath: ${t}`));
|
|
718
|
+
i(!0);
|
|
660
719
|
});
|
|
661
720
|
}));
|
|
662
721
|
}
|
|
@@ -667,65 +726,80 @@ class D {
|
|
|
667
726
|
this.client.end();
|
|
668
727
|
}
|
|
669
728
|
}
|
|
670
|
-
|
|
729
|
+
async function At(s, r, t, e) {
|
|
730
|
+
return new Promise((i, o) => {
|
|
731
|
+
s.on("ready", () => {
|
|
732
|
+
i(s);
|
|
733
|
+
}), s.on("error", (n) => {
|
|
734
|
+
o(new Error(`ssh.connect: error occurred: ${n}`));
|
|
735
|
+
}), s.on("close", () => {
|
|
736
|
+
}), s.connect(r);
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
async function xt(s, r, t, e, i, o) {
|
|
740
|
+
return new Promise((n, c) => {
|
|
741
|
+
r.forwardOut(t, e, i, o, (a, l) => a ? (s.error(`forwardOut.error: ${a}`), c(a)) : n(l));
|
|
742
|
+
});
|
|
743
|
+
}
|
|
744
|
+
const Ot = "minio-2024-12-18T13-15-44Z", kt = "supervisord-0.7.3", Rt = "supervisord_0.7.3_Linux_64-bit";
|
|
671
745
|
function $(s) {
|
|
672
|
-
return
|
|
746
|
+
return u.join(s, "platforma_ssh");
|
|
673
747
|
}
|
|
674
|
-
function
|
|
675
|
-
return
|
|
748
|
+
function v(s) {
|
|
749
|
+
return u.join(s, "platforma_ssh", "binaries");
|
|
676
750
|
}
|
|
677
|
-
function
|
|
678
|
-
return
|
|
751
|
+
function Nt(s, r) {
|
|
752
|
+
return u.join(v(s), `pl-${b()}-${P(r)}`);
|
|
679
753
|
}
|
|
680
|
-
function
|
|
681
|
-
return
|
|
754
|
+
function L(s, r) {
|
|
755
|
+
return u.join(Nt(s, r), "binaries");
|
|
682
756
|
}
|
|
683
|
-
function
|
|
684
|
-
return
|
|
757
|
+
function R(s, r) {
|
|
758
|
+
return u.join(L(s, r), "platforma");
|
|
685
759
|
}
|
|
686
|
-
function
|
|
687
|
-
return
|
|
760
|
+
function Ut(s, r) {
|
|
761
|
+
return u.join(L(s, r), "free-port");
|
|
688
762
|
}
|
|
689
|
-
function
|
|
690
|
-
return
|
|
763
|
+
function z(s, r) {
|
|
764
|
+
return u.join(v(s), `minio-2024-12-18T13-15-44Z-${P(r)}`);
|
|
691
765
|
}
|
|
692
|
-
function
|
|
693
|
-
return
|
|
766
|
+
function Tt(s, r) {
|
|
767
|
+
return u.join(z(s, r), "minio");
|
|
694
768
|
}
|
|
695
|
-
function
|
|
696
|
-
return
|
|
769
|
+
function Bt(s, r) {
|
|
770
|
+
return u.join(v(s), `supervisord-0.7.3-${P(r)}`, Rt);
|
|
697
771
|
}
|
|
698
|
-
function
|
|
699
|
-
return
|
|
772
|
+
function W(s, r) {
|
|
773
|
+
return u.join(Bt(s, r), "supervisord");
|
|
700
774
|
}
|
|
701
|
-
function
|
|
702
|
-
return
|
|
775
|
+
function K(s) {
|
|
776
|
+
return u.join($(s), "supervisor.conf");
|
|
703
777
|
}
|
|
704
|
-
function
|
|
705
|
-
return
|
|
778
|
+
function N(s) {
|
|
779
|
+
return u.join($(s), "connection.txt");
|
|
706
780
|
}
|
|
707
|
-
async function
|
|
708
|
-
const e = await
|
|
781
|
+
async function _t(s, r, t) {
|
|
782
|
+
const e = await O(s, r, t, "--daemon");
|
|
709
783
|
if (e.stderr)
|
|
710
784
|
throw new Error(`Can not run ssh Platforma ${e.stderr}`);
|
|
711
785
|
}
|
|
712
|
-
async function
|
|
713
|
-
const e = await
|
|
786
|
+
async function jt(s, r, t) {
|
|
787
|
+
const e = await O(s, r, t, "ctl shutdown");
|
|
714
788
|
if (e.stderr)
|
|
715
789
|
throw new Error(`Can not stop ssh Platforma ${e.stderr}`);
|
|
716
790
|
}
|
|
717
|
-
async function
|
|
718
|
-
const
|
|
719
|
-
if (
|
|
720
|
-
return s.info(`supervisord ctl status: stderr occurred: ${
|
|
721
|
-
const
|
|
722
|
-
platforma:
|
|
723
|
-
minio:
|
|
791
|
+
async function It(s, r, t, e) {
|
|
792
|
+
const i = await O(r, t, e, "ctl status");
|
|
793
|
+
if (i.stderr)
|
|
794
|
+
return s.info(`supervisord ctl status: stderr occurred: ${i.stderr}, stdout: ${i.stdout}`), !1;
|
|
795
|
+
const o = {
|
|
796
|
+
platforma: U(i.stdout, "platforma"),
|
|
797
|
+
minio: U(i.stdout, "minio")
|
|
724
798
|
};
|
|
725
|
-
return
|
|
799
|
+
return o.platforma && o.minio ? !0 : (o.minio || s.warn("Minio is not running on the server"), o.platforma || s.warn("Platforma is not running on the server"), !1);
|
|
726
800
|
}
|
|
727
|
-
function
|
|
728
|
-
const
|
|
801
|
+
function Ht(s, r, t, e, i, o, n) {
|
|
802
|
+
const c = Object.entries(r).map(([h, d]) => `${h}="${d}"`).join(","), a = F(16).toString("hex"), l = t;
|
|
729
803
|
return `
|
|
730
804
|
[supervisord]
|
|
731
805
|
logfile=${e}/supervisord.log
|
|
@@ -735,42 +809,42 @@ pidfile=${e}/supervisord.pid
|
|
|
735
809
|
[inet_http_server]
|
|
736
810
|
port=127.0.0.1:${l}
|
|
737
811
|
username=default-user
|
|
738
|
-
password=${
|
|
812
|
+
password=${a}
|
|
739
813
|
|
|
740
814
|
[supervisorctl]
|
|
741
815
|
serverurl=http://127.0.0.1:${l}
|
|
742
816
|
username=default-user
|
|
743
|
-
password=${
|
|
817
|
+
password=${a}
|
|
744
818
|
|
|
745
819
|
[program:platforma]
|
|
746
820
|
autostart=true
|
|
747
821
|
depends_on=minio
|
|
748
|
-
command=${n} --config ${
|
|
822
|
+
command=${n} --config ${i}
|
|
749
823
|
directory=${e}
|
|
750
824
|
autorestart=true
|
|
751
825
|
|
|
752
826
|
[program:minio]
|
|
753
827
|
autostart=true
|
|
754
|
-
environment=${
|
|
755
|
-
command=${
|
|
828
|
+
environment=${c}
|
|
829
|
+
command=${o} server ${s}
|
|
756
830
|
directory=${e}
|
|
757
831
|
autorestart=true
|
|
758
832
|
`;
|
|
759
833
|
}
|
|
760
|
-
async function
|
|
761
|
-
const
|
|
834
|
+
async function O(s, r, t, e) {
|
|
835
|
+
const i = W(r, t), o = K(r), n = `${i} --configuration ${o} ${e}`;
|
|
762
836
|
return await s.exec(n);
|
|
763
837
|
}
|
|
764
|
-
function
|
|
765
|
-
return ((
|
|
766
|
-
`).some((
|
|
767
|
-
const [
|
|
768
|
-
return
|
|
838
|
+
function U(s, r) {
|
|
839
|
+
return ((i) => i.replace(/\x1B\[[0-9;]*m/g, ""))(s).split(`
|
|
840
|
+
`).some((i) => {
|
|
841
|
+
const [o, n] = i.trim().split(/\s{2,}/);
|
|
842
|
+
return o === r && n === "Running";
|
|
769
843
|
});
|
|
770
844
|
}
|
|
771
|
-
class
|
|
845
|
+
class q {
|
|
772
846
|
constructor(r, t, e) {
|
|
773
|
-
|
|
847
|
+
w(this, "initState", {});
|
|
774
848
|
this.logger = r, this.sshClient = t, this.username = e;
|
|
775
849
|
}
|
|
776
850
|
info() {
|
|
@@ -781,8 +855,8 @@ class W {
|
|
|
781
855
|
}
|
|
782
856
|
static async init(r, t) {
|
|
783
857
|
try {
|
|
784
|
-
const e = await
|
|
785
|
-
return new
|
|
858
|
+
const e = await x.init(r, t);
|
|
859
|
+
return new q(r, e, f(t.username));
|
|
786
860
|
} catch (e) {
|
|
787
861
|
throw r.error(`Connection error in SshClient.init: ${e}`), e;
|
|
788
862
|
}
|
|
@@ -790,7 +864,7 @@ class W {
|
|
|
790
864
|
async isAlive() {
|
|
791
865
|
const r = await this.getArch(), t = await this.getUserHomeDirectory();
|
|
792
866
|
try {
|
|
793
|
-
return await
|
|
867
|
+
return await It(this.logger, this.sshClient, t, r.arch);
|
|
794
868
|
} catch {
|
|
795
869
|
return !1;
|
|
796
870
|
}
|
|
@@ -798,21 +872,25 @@ class W {
|
|
|
798
872
|
async start() {
|
|
799
873
|
const r = await this.getArch(), t = await this.getUserHomeDirectory();
|
|
800
874
|
try {
|
|
801
|
-
return await
|
|
875
|
+
return await _t(this.sshClient, t, r.arch), await this.checkIsAliveWithInterval();
|
|
802
876
|
} catch (e) {
|
|
803
|
-
const
|
|
804
|
-
throw this.logger.error(
|
|
877
|
+
const i = `ssh.start: error occurred ${e}`;
|
|
878
|
+
throw this.logger.error(i), new Error(i);
|
|
805
879
|
}
|
|
806
880
|
}
|
|
807
881
|
async stop() {
|
|
808
882
|
const r = await this.getArch(), t = await this.getUserHomeDirectory();
|
|
809
883
|
try {
|
|
810
|
-
return await
|
|
884
|
+
return await jt(this.sshClient, t, r.arch), await this.checkIsAliveWithInterval(void 0, void 0, !1);
|
|
811
885
|
} catch (e) {
|
|
812
|
-
const
|
|
813
|
-
throw this.logger.error(
|
|
886
|
+
const i = `ssh.stop: error occurred ${e}`;
|
|
887
|
+
throw this.logger.error(i), new Error(i);
|
|
814
888
|
}
|
|
815
889
|
}
|
|
890
|
+
async reset() {
|
|
891
|
+
const r = await this.getUserHomeDirectory();
|
|
892
|
+
return this.logger.info("pl.reset: Stop Platforma on the server"), await this.stop(), this.logger.info(`pl.reset: Deleting Platforma workDir ${r} on the server`), await this.sshClient.deleteFolder($(r)), !0;
|
|
893
|
+
}
|
|
816
894
|
async platformaInit(r) {
|
|
817
895
|
const t = { localWorkdir: r };
|
|
818
896
|
try {
|
|
@@ -828,7 +906,7 @@ class W {
|
|
|
828
906
|
);
|
|
829
907
|
if (t.binPaths = { ...e, history: void 0 }, t.downloadedBinaries = e.history, t.ports = await this.fetchPorts(t.remoteHome, t.arch), !t.ports.debug.remote || !t.ports.grpc.remote || !t.ports.minioPort.remote || !t.ports.minioConsolePort.remote || !t.ports.monitoring.remote)
|
|
830
908
|
throw new Error("SshPl.platformaInit: remote ports are not defined");
|
|
831
|
-
const
|
|
909
|
+
const i = await at({
|
|
832
910
|
logger: this.logger,
|
|
833
911
|
workingDir: $(t.remoteHome),
|
|
834
912
|
portsMode: {
|
|
@@ -847,100 +925,100 @@ class W {
|
|
|
847
925
|
type: "env"
|
|
848
926
|
}
|
|
849
927
|
});
|
|
850
|
-
t.generatedConfig = { ...
|
|
851
|
-
for (const [
|
|
852
|
-
await this.sshClient.writeFileOnTheServer(
|
|
853
|
-
for (const
|
|
854
|
-
await this.sshClient.createRemoteDirectory(
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
928
|
+
t.generatedConfig = { ...i, filesToCreate: { skipped: "it is too wordy" } };
|
|
929
|
+
for (const [c, a] of Object.entries(i.filesToCreate))
|
|
930
|
+
await this.sshClient.writeFileOnTheServer(c, a), this.logger.info(`Created file ${c}`);
|
|
931
|
+
for (const c of i.dirsToCreate)
|
|
932
|
+
await this.sshClient.createRemoteDirectory(c), this.logger.info(`Created directory ${c}`);
|
|
933
|
+
const o = Ht(
|
|
934
|
+
i.minioConfig.storageDir,
|
|
935
|
+
i.minioConfig.envs,
|
|
858
936
|
await this.getFreePortForPlatformaOnServer(t.remoteHome, t.arch),
|
|
859
|
-
|
|
860
|
-
|
|
937
|
+
i.workingDir,
|
|
938
|
+
i.plConfig.configPath,
|
|
861
939
|
t.binPaths.minioRelPath,
|
|
862
940
|
t.binPaths.downloadedPl
|
|
863
941
|
);
|
|
864
|
-
if (!await this.sshClient.writeFileOnTheServer(
|
|
942
|
+
if (!await this.sshClient.writeFileOnTheServer(K(t.remoteHome), o))
|
|
865
943
|
throw new Error(`Can not write supervisord config on the server ${$(t.remoteHome)}`);
|
|
866
944
|
return t.connectionInfo = {
|
|
867
|
-
plUser:
|
|
868
|
-
plPassword:
|
|
945
|
+
plUser: i.plUser,
|
|
946
|
+
plPassword: i.plPassword,
|
|
869
947
|
ports: t.ports
|
|
870
948
|
}, await this.sshClient.writeFileOnTheServer(
|
|
871
|
-
|
|
949
|
+
N(t.remoteHome),
|
|
872
950
|
JSON.stringify(t.connectionInfo, void 0, 2)
|
|
873
951
|
), await this.start(), t.started = !0, this.initState = t, {
|
|
874
|
-
plUser:
|
|
875
|
-
plPassword:
|
|
952
|
+
plUser: i.plUser,
|
|
953
|
+
plPassword: i.plPassword,
|
|
876
954
|
ports: t.ports
|
|
877
955
|
};
|
|
878
956
|
} catch (e) {
|
|
879
|
-
const
|
|
880
|
-
throw this.logger.error(
|
|
957
|
+
const i = `SshPl.platformaInit: error occurred: ${e}, state: ${JSON.stringify(t)}`;
|
|
958
|
+
throw this.logger.error(i), new Error(i);
|
|
881
959
|
}
|
|
882
960
|
}
|
|
883
961
|
async downloadBinariesAndUploadToTheServer(r, t, e) {
|
|
884
|
-
const
|
|
962
|
+
const i = [];
|
|
885
963
|
try {
|
|
886
|
-
const
|
|
964
|
+
const o = await this.downloadAndUntar(
|
|
887
965
|
r,
|
|
888
966
|
t,
|
|
889
967
|
e,
|
|
890
968
|
"pl",
|
|
891
969
|
`pl-${b()}`
|
|
892
970
|
);
|
|
893
|
-
|
|
971
|
+
i.push(o);
|
|
894
972
|
const n = await this.downloadAndUntar(
|
|
895
973
|
r,
|
|
896
974
|
t,
|
|
897
975
|
e,
|
|
898
976
|
"supervisord",
|
|
899
|
-
|
|
977
|
+
kt
|
|
900
978
|
);
|
|
901
|
-
|
|
902
|
-
const
|
|
979
|
+
i.push(n);
|
|
980
|
+
const c = Tt(t, e.arch), a = await this.downloadAndUntar(
|
|
903
981
|
r,
|
|
904
982
|
t,
|
|
905
983
|
e,
|
|
906
984
|
"minio",
|
|
907
|
-
|
|
985
|
+
Ot
|
|
908
986
|
);
|
|
909
|
-
return
|
|
910
|
-
history:
|
|
911
|
-
minioRelPath:
|
|
912
|
-
downloadedPl:
|
|
987
|
+
return i.push(a), await this.sshClient.chmod(c, 488), {
|
|
988
|
+
history: i,
|
|
989
|
+
minioRelPath: c,
|
|
990
|
+
downloadedPl: R(t, e.arch)
|
|
913
991
|
};
|
|
914
|
-
} catch (
|
|
915
|
-
const n = `SshPl.downloadBinariesAndUploadToServer: error ${
|
|
916
|
-
throw this.logger.error(n),
|
|
992
|
+
} catch (o) {
|
|
993
|
+
const n = `SshPl.downloadBinariesAndUploadToServer: error ${o} occurred, state: ${JSON.stringify(i)}`;
|
|
994
|
+
throw this.logger.error(n), o;
|
|
917
995
|
}
|
|
918
996
|
}
|
|
919
997
|
/** We have to extract pl in the remote server,
|
|
920
998
|
* because Windows doesn't support symlinks
|
|
921
999
|
* that are found in linux pl binaries tgz archive.
|
|
922
1000
|
* For this reason, we extract all to the remote server. */
|
|
923
|
-
async downloadAndUntar(r, t, e,
|
|
1001
|
+
async downloadAndUntar(r, t, e, i, o) {
|
|
924
1002
|
const n = {};
|
|
925
|
-
n.binBasePath =
|
|
926
|
-
let
|
|
927
|
-
const
|
|
928
|
-
for (let
|
|
1003
|
+
n.binBasePath = v(t), await this.sshClient.createRemoteDirectory(n.binBasePath), n.binBasePathCreated = !0;
|
|
1004
|
+
let c = null;
|
|
1005
|
+
const a = 5;
|
|
1006
|
+
for (let h = 1; h <= a; h++)
|
|
929
1007
|
try {
|
|
930
|
-
|
|
1008
|
+
c = await ut(
|
|
931
1009
|
this.logger,
|
|
932
1010
|
r,
|
|
933
|
-
o,
|
|
934
1011
|
i,
|
|
1012
|
+
o,
|
|
935
1013
|
e.arch,
|
|
936
1014
|
e.platform
|
|
937
1015
|
);
|
|
938
1016
|
break;
|
|
939
|
-
} catch (
|
|
940
|
-
if (await
|
|
941
|
-
throw new Error(`downloadAndUntar: ${
|
|
1017
|
+
} catch (d) {
|
|
1018
|
+
if (await C(300), h == a)
|
|
1019
|
+
throw new Error(`downloadAndUntar: ${a} attempts, last error: ${d}`);
|
|
942
1020
|
}
|
|
943
|
-
n.downloadResult =
|
|
1021
|
+
n.downloadResult = f(c), n.localArchivePath = u.resolve(n.downloadResult.archivePath), n.remoteDir = u.join(n.binBasePath, n.downloadResult.baseName), n.remoteArchivePath = n.remoteDir + ".tgz", await this.sshClient.createRemoteDirectory(n.remoteDir), await this.sshClient.uploadFile(n.localArchivePath, n.remoteArchivePath);
|
|
944
1022
|
const l = await this.sshClient.exec(
|
|
945
1023
|
`tar xvf ${n.remoteArchivePath} --directory=${n.remoteDir}`
|
|
946
1024
|
);
|
|
@@ -949,20 +1027,20 @@ class W {
|
|
|
949
1027
|
return n.plUntarDone = !0, n;
|
|
950
1028
|
}
|
|
951
1029
|
async needDownload(r, t) {
|
|
952
|
-
const e =
|
|
953
|
-
return !await this.sshClient.checkFileExists(
|
|
1030
|
+
const e = W(r, t.arch), i = z(r, t.arch), o = R(r, t.arch);
|
|
1031
|
+
return !await this.sshClient.checkFileExists(o) || !await this.sshClient.checkFileExists(i) || !await this.sshClient.checkFileExists(e);
|
|
954
1032
|
}
|
|
955
1033
|
async checkIsAliveWithInterval(r = 1e3, t = 15, e = !0) {
|
|
956
|
-
const
|
|
957
|
-
let
|
|
1034
|
+
const i = t * r;
|
|
1035
|
+
let o = 0, n = await this.isAlive();
|
|
958
1036
|
for (; e ? !n : n; ) {
|
|
959
|
-
if (await
|
|
960
|
-
throw new Error(`isAliveWithInterval: The process did not ${e ? "started" : "stopped"} after ${
|
|
1037
|
+
if (await C(r), o += r, o > i)
|
|
1038
|
+
throw new Error(`isAliveWithInterval: The process did not ${e ? "started" : "stopped"} after ${i} ms.`);
|
|
961
1039
|
n = await this.isAlive();
|
|
962
1040
|
}
|
|
963
1041
|
}
|
|
964
1042
|
async getUserCredentials(r) {
|
|
965
|
-
const t = await this.sshClient.readFile(
|
|
1043
|
+
const t = await this.sshClient.readFile(N(r));
|
|
966
1044
|
return JSON.parse(t);
|
|
967
1045
|
}
|
|
968
1046
|
async fetchPorts(r, t) {
|
|
@@ -991,18 +1069,18 @@ class W {
|
|
|
991
1069
|
}
|
|
992
1070
|
async getLocalFreePort() {
|
|
993
1071
|
return new Promise((r) => {
|
|
994
|
-
const t =
|
|
1072
|
+
const t = B.createServer();
|
|
995
1073
|
t.listen(0, () => {
|
|
996
1074
|
const e = t.address().port;
|
|
997
|
-
t.close((
|
|
1075
|
+
t.close((i) => r(e));
|
|
998
1076
|
});
|
|
999
1077
|
});
|
|
1000
1078
|
}
|
|
1001
1079
|
async getFreePortForPlatformaOnServer(r, t) {
|
|
1002
|
-
const e =
|
|
1003
|
-
if (
|
|
1004
|
-
throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${
|
|
1005
|
-
return +
|
|
1080
|
+
const e = Ut(r, t.arch), { stdout: i, stderr: o } = await this.sshClient.exec(`${e}`);
|
|
1081
|
+
if (o)
|
|
1082
|
+
throw new Error(`getFreePortForPlatformaOnServer: stderr is not empty: ${o}, stdout: ${i}`);
|
|
1083
|
+
return +i;
|
|
1006
1084
|
}
|
|
1007
1085
|
async getArch() {
|
|
1008
1086
|
const { stdout: r, stderr: t } = await this.sshClient.exec("uname -s && uname -m");
|
|
@@ -1025,11 +1103,11 @@ class W {
|
|
|
1025
1103
|
}
|
|
1026
1104
|
}
|
|
1027
1105
|
export {
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1106
|
+
Et as LocalConfigYaml,
|
|
1107
|
+
Ft as LocalPl,
|
|
1108
|
+
x as SshClient,
|
|
1109
|
+
q as SshPl,
|
|
1032
1110
|
b as getDefaultPlVersion,
|
|
1033
|
-
|
|
1111
|
+
ir as localPlatformaInit
|
|
1034
1112
|
};
|
|
1035
1113
|
//# sourceMappingURL=index.mjs.map
|