@milaboratories/pl-deployments 2.15.7 → 2.15.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -5
- package/dist/common/os_and_arch.cjs +19 -19
- package/dist/common/os_and_arch.cjs.map +1 -1
- package/dist/common/os_and_arch.js +19 -19
- package/dist/common/os_and_arch.js.map +1 -1
- package/dist/common/pl_binary.cjs +9 -9
- package/dist/common/pl_binary.cjs.map +1 -1
- package/dist/common/pl_binary.d.ts +6 -6
- package/dist/common/pl_binary.d.ts.map +1 -1
- package/dist/common/pl_binary.js +9 -9
- package/dist/common/pl_binary.js.map +1 -1
- package/dist/common/pl_binary_download.cjs +16 -16
- package/dist/common/pl_binary_download.cjs.map +1 -1
- package/dist/common/pl_binary_download.d.ts +6 -6
- package/dist/common/pl_binary_download.d.ts.map +1 -1
- package/dist/common/pl_binary_download.js +16 -16
- package/dist/common/pl_binary_download.js.map +1 -1
- package/dist/common/pl_version.cjs +1 -1
- package/dist/common/pl_version.cjs.map +1 -1
- package/dist/common/pl_version.js +1 -1
- package/dist/common/pl_version.js.map +1 -1
- package/dist/index.d.ts +5 -5
- package/dist/local/options.d.ts +4 -4
- package/dist/local/pid.cjs +1 -1
- package/dist/local/pid.cjs.map +1 -1
- package/dist/local/pid.js +1 -1
- package/dist/local/pid.js.map +1 -1
- package/dist/local/pl.cjs +26 -26
- package/dist/local/pl.cjs.map +1 -1
- package/dist/local/pl.d.ts +8 -8
- package/dist/local/pl.d.ts.map +1 -1
- package/dist/local/pl.js +26 -26
- package/dist/local/pl.js.map +1 -1
- package/dist/local/process.cjs +16 -16
- package/dist/local/process.cjs.map +1 -1
- package/dist/local/process.d.ts +2 -2
- package/dist/local/process.js +16 -16
- package/dist/local/process.js.map +1 -1
- package/dist/local/trace.cjs.map +1 -1
- package/dist/local/trace.d.ts +1 -1
- package/dist/local/trace.js.map +1 -1
- package/dist/package.json.cjs +2 -1
- package/dist/package.json.cjs.map +1 -1
- package/dist/package.json.js +2 -1
- package/dist/package.json.js.map +1 -1
- package/dist/ssh/__tests__/common-utils.d.ts +2 -2
- package/dist/ssh/__tests__/common-utils.d.ts.map +1 -1
- package/dist/ssh/connection_info.cjs +13 -7
- package/dist/ssh/connection_info.cjs.map +1 -1
- package/dist/ssh/connection_info.d.ts +1 -1
- package/dist/ssh/connection_info.d.ts.map +1 -1
- package/dist/ssh/connection_info.js +13 -7
- package/dist/ssh/connection_info.js.map +1 -1
- package/dist/ssh/pl.cjs +79 -76
- package/dist/ssh/pl.cjs.map +1 -1
- package/dist/ssh/pl.d.ts +18 -18
- package/dist/ssh/pl.d.ts.map +1 -1
- package/dist/ssh/pl.js +79 -76
- package/dist/ssh/pl.js.map +1 -1
- package/dist/ssh/pl_paths.cjs +13 -13
- package/dist/ssh/pl_paths.cjs.map +1 -1
- package/dist/ssh/pl_paths.d.ts.map +1 -1
- package/dist/ssh/pl_paths.js +13 -13
- package/dist/ssh/pl_paths.js.map +1 -1
- package/dist/ssh/ssh.cjs +43 -40
- package/dist/ssh/ssh.cjs.map +1 -1
- package/dist/ssh/ssh.d.ts +9 -9
- package/dist/ssh/ssh.d.ts.map +1 -1
- package/dist/ssh/ssh.js +43 -40
- package/dist/ssh/ssh.js.map +1 -1
- package/dist/ssh/ssh_errors.cjs +7 -5
- package/dist/ssh/ssh_errors.cjs.map +1 -1
- package/dist/ssh/ssh_errors.d.ts.map +1 -1
- package/dist/ssh/ssh_errors.js +7 -5
- package/dist/ssh/ssh_errors.js.map +1 -1
- package/dist/ssh/supervisord.cjs +15 -13
- package/dist/ssh/supervisord.cjs.map +1 -1
- package/dist/ssh/supervisord.d.ts +2 -2
- package/dist/ssh/supervisord.d.ts.map +1 -1
- package/dist/ssh/supervisord.js +15 -13
- package/dist/ssh/supervisord.js.map +1 -1
- package/package.json +38 -37
- package/src/common/os_and_arch.ts +19 -19
- package/src/common/pl_binary.ts +30 -27
- package/src/common/pl_binary_download.ts +80 -59
- package/src/common/pl_version.ts +2 -2
- package/src/index.ts +5 -5
- package/src/local/config.test.yaml +19 -19
- package/src/local/options.ts +4 -4
- package/src/local/pid.ts +4 -4
- package/src/local/pl.test.ts +245 -253
- package/src/local/pl.ts +45 -50
- package/src/local/process.ts +21 -21
- package/src/local/trace.ts +1 -1
- package/src/ssh/__tests__/common-utils.ts +21 -19
- package/src/ssh/__tests__/pl-docker.test.ts +68 -59
- package/src/ssh/__tests__/ssh-docker.test.ts +152 -90
- package/src/ssh/__tests__/ssh-upload.test.ts +42 -31
- package/src/ssh/connection_info.ts +33 -27
- package/src/ssh/pl.test.ts +15 -13
- package/src/ssh/pl.ts +228 -143
- package/src/ssh/pl_paths.ts +22 -18
- package/src/ssh/ssh.ts +151 -74
- package/src/ssh/ssh_errors.test.ts +39 -39
- package/src/ssh/ssh_errors.ts +8 -6
- package/src/ssh/supervisord.ts +28 -28
|
@@ -1,90 +1,90 @@
|
|
|
1
|
-
import { describe, test, expect } from
|
|
2
|
-
import { SFTPError, SSHError, SFTPUploadError } from
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { SFTPError, SSHError, SFTPUploadError } from "./ssh_errors";
|
|
3
3
|
|
|
4
|
-
test(
|
|
5
|
-
const err = new Error(
|
|
6
|
-
const uploadErr = new SFTPUploadError(err,
|
|
4
|
+
test("error chain unwrapping works", () => {
|
|
5
|
+
const err = new Error("Failure");
|
|
6
|
+
const uploadErr = new SFTPUploadError(err, "localPath", "remotePath");
|
|
7
7
|
const finalErr = new Error(`Problem: ${uploadErr.message}`, { cause: uploadErr });
|
|
8
8
|
|
|
9
9
|
expect(SFTPUploadError.from(finalErr)).toBe(uploadErr);
|
|
10
10
|
expect(SFTPError.from(finalErr)).toBeDefined();
|
|
11
11
|
expect(SSHError.from(finalErr)).toBeDefined();
|
|
12
|
-
})
|
|
12
|
+
});
|
|
13
13
|
|
|
14
|
-
describe(
|
|
15
|
-
test(
|
|
16
|
-
const err = new SSHError(
|
|
17
|
-
expect(err.message).toBe(
|
|
14
|
+
describe("SSHError", () => {
|
|
15
|
+
test("should add prefix to error message", () => {
|
|
16
|
+
const err = new SSHError("Test error");
|
|
17
|
+
expect(err.message).toBe("SSHError: Test error");
|
|
18
18
|
});
|
|
19
19
|
|
|
20
|
-
test(
|
|
21
|
-
const cause = new Error(
|
|
22
|
-
const err = new SSHError(
|
|
20
|
+
test("should respect cause option", () => {
|
|
21
|
+
const cause = new Error("Cause error");
|
|
22
|
+
const err = new SSHError("Test error", { cause });
|
|
23
23
|
expect(err.cause).toBe(cause);
|
|
24
|
-
})
|
|
24
|
+
});
|
|
25
25
|
|
|
26
|
-
test(
|
|
27
|
-
const cause = new Error(
|
|
26
|
+
test("should preserve original error as cause", () => {
|
|
27
|
+
const cause = new Error("Cause error");
|
|
28
28
|
const err = new SSHError(cause);
|
|
29
29
|
expect(err.cause).toBe(cause);
|
|
30
|
-
})
|
|
30
|
+
});
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
describe(
|
|
34
|
-
test(
|
|
33
|
+
describe("SFTPError.wrap()", () => {
|
|
34
|
+
test("should return undefined when err is undefined", () => {
|
|
35
35
|
const result = SFTPError.wrap(undefined);
|
|
36
36
|
expect(result).toBeUndefined();
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
test(
|
|
40
|
-
const sftpErr = new SFTPError(
|
|
39
|
+
test("should return the same error when err is already an SFTPError", () => {
|
|
40
|
+
const sftpErr = new SFTPError("Failure");
|
|
41
41
|
const result = SFTPError.wrap(sftpErr);
|
|
42
42
|
expect(result).toBe(sftpErr);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
test(
|
|
46
|
-
const regularErr = new Error(
|
|
45
|
+
test("should wrap a regular Error in SFTPError", () => {
|
|
46
|
+
const regularErr = new Error("Some error message");
|
|
47
47
|
const result = SFTPError.wrap(regularErr);
|
|
48
48
|
|
|
49
49
|
expect(result).toBeInstanceOf(SFTPError);
|
|
50
50
|
expect(result).not.toBe(regularErr);
|
|
51
|
-
expect(result?.code).toBe(
|
|
51
|
+
expect(result?.code).toBe("Some error message");
|
|
52
52
|
expect(result?.cause).toBe(regularErr);
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
test(
|
|
56
|
-
const originalSftpErr = new SFTPError(
|
|
57
|
-
const wrappedErr = new Error(
|
|
55
|
+
test("should return existing SFTPError when err has SFTPError in cause chain", () => {
|
|
56
|
+
const originalSftpErr = new SFTPError("Permission denied");
|
|
57
|
+
const wrappedErr = new Error("Outer error", { cause: originalSftpErr });
|
|
58
58
|
const result = SFTPError.wrap(wrappedErr);
|
|
59
59
|
|
|
60
60
|
expect(result).toBe(originalSftpErr);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
test(
|
|
64
|
-
const sshErr = new SSHError(
|
|
63
|
+
test("should wrap SSHError that is not SFTPError", () => {
|
|
64
|
+
const sshErr = new SSHError("SSH connection failed");
|
|
65
65
|
const result = SFTPError.wrap(sshErr);
|
|
66
66
|
|
|
67
67
|
expect(result).toBeInstanceOf(SFTPError);
|
|
68
68
|
expect(result).not.toBe(sshErr);
|
|
69
|
-
expect(result?.code).toBe(
|
|
69
|
+
expect(result?.code).toBe("SSHError: SSH connection failed");
|
|
70
70
|
expect(result?.cause).toBe(sshErr);
|
|
71
71
|
});
|
|
72
72
|
|
|
73
|
-
test(
|
|
74
|
-
const originalSftpErr = new SFTPError(
|
|
75
|
-
const intermediateErr1 = new Error(
|
|
76
|
-
const intermediateErr2 = new Error(
|
|
77
|
-
const finalErr = new Error(
|
|
73
|
+
test("should wrap error with SFTPError deep in cause chain", () => {
|
|
74
|
+
const originalSftpErr = new SFTPError("File not found");
|
|
75
|
+
const intermediateErr1 = new Error("Intermediate 1", { cause: originalSftpErr });
|
|
76
|
+
const intermediateErr2 = new Error("Intermediate 2", { cause: intermediateErr1 });
|
|
77
|
+
const finalErr = new Error("Final error", { cause: intermediateErr2 });
|
|
78
78
|
const result = SFTPError.wrap(finalErr);
|
|
79
79
|
|
|
80
80
|
expect(result).toBe(originalSftpErr);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
test(
|
|
84
|
-
const err = new Error(
|
|
83
|
+
test("should preserve error message when wrapping", () => {
|
|
84
|
+
const err = new Error("Custom error message");
|
|
85
85
|
const result = SFTPError.wrap(err);
|
|
86
86
|
|
|
87
|
-
expect(result?.code).toBe(
|
|
88
|
-
expect(result?.message).toContain(
|
|
87
|
+
expect(result?.code).toBe("Custom error message");
|
|
88
|
+
expect(result?.message).toContain("Custom error message");
|
|
89
89
|
});
|
|
90
90
|
});
|
package/src/ssh/ssh_errors.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { findNamedErrorInCauses } from
|
|
1
|
+
import { findNamedErrorInCauses } from "@milaboratories/ts-helpers";
|
|
2
2
|
|
|
3
3
|
const MAX_UNWRAP_DEPTH = 10;
|
|
4
4
|
|
|
5
5
|
export class SSHError extends Error {
|
|
6
|
-
name =
|
|
6
|
+
name = "SSHError";
|
|
7
7
|
|
|
8
8
|
constructor(message: string, opts?: { cause: Error });
|
|
9
9
|
constructor(err: Error);
|
|
@@ -21,7 +21,7 @@ export class SSHError extends Error {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
export class SFTPError extends SSHError {
|
|
24
|
-
name =
|
|
24
|
+
name = "SFTPError";
|
|
25
25
|
|
|
26
26
|
constructor(
|
|
27
27
|
public readonly code: string, // raw SFTP error code, i.e. from OpenSSH server
|
|
@@ -48,19 +48,21 @@ export class SFTPError extends SSHError {
|
|
|
48
48
|
// OpenSSH server returns this message in case of general failure.
|
|
49
49
|
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-server.c#L244
|
|
50
50
|
// See https://github.com/openssh/openssh-portable/blob/1cc936b2fabffeac7fff14ca1070d7d7a317ab7b/sftp-common.c#L195
|
|
51
|
-
return this.code ===
|
|
51
|
+
return this.code === "Failure";
|
|
52
52
|
}
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
export class SFTPUploadError extends SSHError {
|
|
56
|
-
name =
|
|
56
|
+
name = "SFTPUploadError";
|
|
57
57
|
|
|
58
58
|
constructor(
|
|
59
59
|
err: Error,
|
|
60
60
|
public readonly localPath: string,
|
|
61
61
|
public readonly remotePath: string,
|
|
62
62
|
) {
|
|
63
|
-
super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, {
|
|
63
|
+
super(`ssh.uploadFile: ${err.message}, localPath: ${localPath}, remotePath: ${remotePath}`, {
|
|
64
|
+
cause: SFTPError.wrap(err),
|
|
65
|
+
});
|
|
64
66
|
}
|
|
65
67
|
|
|
66
68
|
static from(err: unknown): SFTPUploadError | undefined {
|
package/src/ssh/supervisord.ts
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
/** Provides helper functions to work with supervisord */
|
|
2
2
|
|
|
3
|
-
import type { MiLogger } from
|
|
4
|
-
import * as plpath from
|
|
5
|
-
import type { SshClient, SshExecResult } from
|
|
6
|
-
import { randomBytes } from
|
|
3
|
+
import type { MiLogger } from "@milaboratories/ts-helpers";
|
|
4
|
+
import * as plpath from "./pl_paths";
|
|
5
|
+
import type { SshClient, SshExecResult } from "./ssh";
|
|
6
|
+
import { randomBytes } from "node:crypto";
|
|
7
7
|
|
|
8
|
-
export async function supervisorCtlStart(
|
|
9
|
-
sshClient
|
|
10
|
-
remoteHome: string, arch: string,
|
|
11
|
-
) {
|
|
12
|
-
const result = await supervisorExec(sshClient, remoteHome, arch, '--daemon');
|
|
8
|
+
export async function supervisorCtlStart(sshClient: SshClient, remoteHome: string, arch: string) {
|
|
9
|
+
const result = await supervisorExec(sshClient, remoteHome, arch, "--daemon");
|
|
13
10
|
|
|
14
11
|
if (result.stderr) {
|
|
15
12
|
throw new Error(`Can not run ssh Platforma ${result.stderr}`);
|
|
16
13
|
}
|
|
17
14
|
}
|
|
18
15
|
|
|
19
|
-
export async function supervisorStop(
|
|
20
|
-
sshClient
|
|
21
|
-
remoteHome: string, arch: string,
|
|
22
|
-
) {
|
|
23
|
-
const result = await supervisorExec(sshClient, remoteHome, arch, 'ctl shutdown');
|
|
16
|
+
export async function supervisorStop(sshClient: SshClient, remoteHome: string, arch: string) {
|
|
17
|
+
const result = await supervisorExec(sshClient, remoteHome, arch, "ctl shutdown");
|
|
24
18
|
|
|
25
19
|
if (result.stderr) {
|
|
26
20
|
throw new Error(`Can not stop ssh Platforma ${result.stderr}`);
|
|
@@ -51,23 +45,26 @@ export function isSupervisordRunning(status: SupervisorStatus) {
|
|
|
51
45
|
export async function supervisorStatus(
|
|
52
46
|
logger: MiLogger,
|
|
53
47
|
sshClient: SshClient,
|
|
54
|
-
remoteHome: string,
|
|
48
|
+
remoteHome: string,
|
|
49
|
+
arch: string,
|
|
55
50
|
): Promise<SupervisorStatus> {
|
|
56
51
|
let result: SshExecResult;
|
|
57
52
|
try {
|
|
58
|
-
result = await supervisorExec(sshClient, remoteHome, arch,
|
|
53
|
+
result = await supervisorExec(sshClient, remoteHome, arch, "ctl status");
|
|
59
54
|
} catch (e: unknown) {
|
|
60
55
|
return { execError: String(e) };
|
|
61
56
|
}
|
|
62
57
|
|
|
63
58
|
if (result.stderr) {
|
|
64
|
-
logger.info(
|
|
59
|
+
logger.info(
|
|
60
|
+
`supervisord ctl status: stderr occurred: ${result.stderr}, stdout: ${result.stdout}`,
|
|
61
|
+
);
|
|
65
62
|
|
|
66
63
|
return { rawResult: result };
|
|
67
64
|
}
|
|
68
65
|
|
|
69
|
-
const platforma = isProgramRunning(result.stdout,
|
|
70
|
-
const minio = isProgramRunning(result.stdout,
|
|
66
|
+
const platforma = isProgramRunning(result.stdout, "platforma");
|
|
67
|
+
const minio = isProgramRunning(result.stdout, "minio");
|
|
71
68
|
const status: SupervisorStatus = {
|
|
72
69
|
rawResult: result,
|
|
73
70
|
platforma,
|
|
@@ -75,11 +72,11 @@ export async function supervisorStatus(
|
|
|
75
72
|
};
|
|
76
73
|
|
|
77
74
|
if (!status.minio) {
|
|
78
|
-
logger.warn(
|
|
75
|
+
logger.warn("Minio is not running on the server");
|
|
79
76
|
}
|
|
80
77
|
|
|
81
78
|
if (!status.platforma) {
|
|
82
|
-
logger.warn(
|
|
79
|
+
logger.warn("Platforma is not running on the server");
|
|
83
80
|
}
|
|
84
81
|
|
|
85
82
|
return status;
|
|
@@ -94,7 +91,7 @@ export function generateSupervisordConfig(
|
|
|
94
91
|
platformaConfigPath: string,
|
|
95
92
|
plPath: string,
|
|
96
93
|
) {
|
|
97
|
-
const password = randomBytes(16).toString(
|
|
94
|
+
const password = randomBytes(16).toString("hex");
|
|
98
95
|
const freePort = supervisorRemotePort;
|
|
99
96
|
|
|
100
97
|
return `
|
|
@@ -137,8 +134,10 @@ export function generateSupervisordConfigWithMinio(
|
|
|
137
134
|
minioPath: string,
|
|
138
135
|
plPath: string,
|
|
139
136
|
) {
|
|
140
|
-
const minioEnvStr = Object.entries(minioEnvs)
|
|
141
|
-
|
|
137
|
+
const minioEnvStr = Object.entries(minioEnvs)
|
|
138
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
139
|
+
.join(",");
|
|
140
|
+
const password = randomBytes(16).toString("hex");
|
|
142
141
|
const freePort = supervisorRemotePort;
|
|
143
142
|
|
|
144
143
|
return `
|
|
@@ -175,7 +174,8 @@ autorestart=true
|
|
|
175
174
|
|
|
176
175
|
export async function supervisorExec(
|
|
177
176
|
sshClient: SshClient,
|
|
178
|
-
remoteHome: string,
|
|
177
|
+
remoteHome: string,
|
|
178
|
+
arch: string,
|
|
179
179
|
command: string,
|
|
180
180
|
) {
|
|
181
181
|
const supervisorCmd = plpath.supervisorBin(remoteHome, arch);
|
|
@@ -187,13 +187,13 @@ export async function supervisorExec(
|
|
|
187
187
|
|
|
188
188
|
function isProgramRunning(output: string, programName: string) {
|
|
189
189
|
// eslint-disable-next-line no-control-regex
|
|
190
|
-
const stripAnsi = (str: string) => str.replace(/\x1B\[[0-9;]*m/g,
|
|
190
|
+
const stripAnsi = (str: string) => str.replace(/\x1B\[[0-9;]*m/g, "");
|
|
191
191
|
|
|
192
192
|
const cleanedOutput = stripAnsi(output);
|
|
193
193
|
|
|
194
|
-
return cleanedOutput.split(
|
|
194
|
+
return cleanedOutput.split("\n").some((line) => {
|
|
195
195
|
const [name, status] = line.trim().split(/\s{2,}/); // Split string by 2 spaces.
|
|
196
196
|
|
|
197
|
-
return name === programName && status ===
|
|
197
|
+
return name === programName && status === "Running";
|
|
198
198
|
});
|
|
199
199
|
}
|