ssh-client-wrapper 2.5.0 → 2.6.1
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/lib/fork.js +5 -0
- package/lib/sshExec.js +1 -1
- package/lib/util.js +19 -4
- package/package.json +1 -1
- package/test/getSshOption.js +49 -0
- /package/test/{util.js → sanityCheck.js} +0 -0
package/lib/fork.js
CHANGED
|
@@ -96,6 +96,11 @@ async function fork (hostInfo, cmd, args, timeout, outputCallback, retryableExit
|
|
|
96
96
|
err.retryable = true;
|
|
97
97
|
reject(err);
|
|
98
98
|
}
|
|
99
|
+
if (/muxserver_listen: link mux listener .* Bad file descriptor/.test(output)) {
|
|
100
|
+
ptyProcess.kill();
|
|
101
|
+
const err = new Error("Control socket creation failed");
|
|
102
|
+
reject(err);
|
|
103
|
+
}
|
|
99
104
|
});
|
|
100
105
|
}
|
|
101
106
|
|
package/lib/sshExec.js
CHANGED
|
@@ -247,7 +247,7 @@ async function ls (hostInfo, target, lsOpt, timeout) {
|
|
|
247
247
|
* @param {Integer} argMaxRetry - max retry number
|
|
248
248
|
*/
|
|
249
249
|
async function retryWrapper (func, hostInfo, argMaxRetry, argDuration) {
|
|
250
|
-
const maxRetry = argMaxRetry || hostInfo.maxRetry ||
|
|
250
|
+
const maxRetry = argMaxRetry || hostInfo.maxRetry || 3;
|
|
251
251
|
const duration = argDuration || hostInfo.retryDuration || 1000;
|
|
252
252
|
if (maxRetry === 1) {
|
|
253
253
|
return func();
|
package/lib/util.js
CHANGED
|
@@ -37,6 +37,7 @@ const hostInfoSchema = {
|
|
|
37
37
|
noStrictHostkeyChecking: { type: "boolean" },
|
|
38
38
|
ControlPersist: { type: "number", minimum: 0, default: 180 },
|
|
39
39
|
ConnectTimeout: { type: "number", minimum: 0 },
|
|
40
|
+
ControlPersistDir: { type: "string", pattern: "\\S+", transform: ["trim"] },
|
|
40
41
|
maxRetry: { type: "number", minimum: 0, default: 3 },
|
|
41
42
|
retryDuration: { type: "number", minimum: 0, default: 1000 },
|
|
42
43
|
sshOpt: { type: "array", minItems: 1, items: { type: "string", pattern: "\\S+", transform: ["trim"] } }
|
|
@@ -46,7 +47,8 @@ const hostInfoSchema = {
|
|
|
46
47
|
|
|
47
48
|
const stringOptions = [
|
|
48
49
|
"user",
|
|
49
|
-
"keyFile"
|
|
50
|
+
"keyFile",
|
|
51
|
+
"ControlPersistDir"
|
|
50
52
|
];
|
|
51
53
|
const numberOptions = [
|
|
52
54
|
"ControlPersist",
|
|
@@ -130,6 +132,18 @@ const sanityCheck = (hostInfo) => {
|
|
|
130
132
|
return hostInfo;
|
|
131
133
|
};
|
|
132
134
|
|
|
135
|
+
function getControlPersistDir (hostInfo) {
|
|
136
|
+
for (const candidate of [hostInfo.ControlPersistDir, process.env.SSH_CONTROL_PERSIST_DIR]) {
|
|
137
|
+
if (typeof candidate === "string") {
|
|
138
|
+
const stat = fs.statSync(candidate, { throwIfNoEntry: false });
|
|
139
|
+
if (stat.isDirectory()) {
|
|
140
|
+
return candidate;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return "~/.ssh";
|
|
145
|
+
}
|
|
146
|
+
|
|
133
147
|
/**
|
|
134
148
|
* return ssh option with some hard corded options
|
|
135
149
|
* @param { Object} hostInfo - host information object defined in index.js
|
|
@@ -179,10 +193,11 @@ const getSshOption = (hostInfo, withoutDestination) => {
|
|
|
179
193
|
if (hostInfo.noStrictHostkeyChecking) {
|
|
180
194
|
args.push("-oStrictHostKeyChecking=no");
|
|
181
195
|
}
|
|
182
|
-
const
|
|
196
|
+
const controlPersist = Number.isInteger(hostInfo.ControlPersist) && hostInfo.ControlPersist >= 0 ? hostInfo.ControlPersist : "180";
|
|
197
|
+
const controlPersistDir = getControlPersistDir(hostInfo);
|
|
183
198
|
args.push("-oControlMaster=auto");
|
|
184
|
-
args.push(
|
|
185
|
-
args.push(`-oControlPersist=${
|
|
199
|
+
args.push(`-oControlPath=${controlPersistDir}/ssh-client-wrapper-%r@%h:%p`);
|
|
200
|
+
args.push(`-oControlPersist=${controlPersist}`);
|
|
186
201
|
|
|
187
202
|
if (Number.isInteger(hostInfo.ConnectTimeout) && hostInfo.ConnectTimeout > 0) {
|
|
188
203
|
args.push(`-oConnectTimeout=${hostInfo.ConnectTimeout}`);
|
package/package.json
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
process.on("unhandledRejection", console.dir); // eslint-disable-line no-console
|
|
3
|
+
|
|
4
|
+
// setup test framework
|
|
5
|
+
const chai = require("chai");
|
|
6
|
+
const { expect } = require("chai");
|
|
7
|
+
chai.use(require("chai-as-promised"));
|
|
8
|
+
|
|
9
|
+
// testee
|
|
10
|
+
const { getSshOption } = require("../lib/util.js");
|
|
11
|
+
|
|
12
|
+
describe("test for getSshOption", () => {
|
|
13
|
+
const defaultValues = {
|
|
14
|
+
host: "testHostName",
|
|
15
|
+
ControlPersist: 180,
|
|
16
|
+
maxRetry: 3,
|
|
17
|
+
retryDuration: 1000
|
|
18
|
+
};
|
|
19
|
+
it("should return minimum ssh option array", () => {
|
|
20
|
+
const sshOpts = getSshOption(defaultValues);
|
|
21
|
+
expect(sshOpts).to.be.an("array");
|
|
22
|
+
expect(sshOpts).to.have.lengthOf(4);
|
|
23
|
+
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
24
|
+
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
25
|
+
expect(sshOpts[2]).to.equal("-oControlPath=~/.ssh/ssh-client-wrapper-%r@%h:%p");
|
|
26
|
+
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
27
|
+
});
|
|
28
|
+
it("should change ControlPath by ControlPersistDir", () => {
|
|
29
|
+
const hostInfo = { ...defaultValues };
|
|
30
|
+
hostInfo.ControlPersistDir = "/tmp";
|
|
31
|
+
const sshOpts = getSshOption(hostInfo);
|
|
32
|
+
expect(sshOpts).to.be.an("array");
|
|
33
|
+
expect(sshOpts).to.have.lengthOf(4);
|
|
34
|
+
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
35
|
+
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
36
|
+
expect(sshOpts[2]).to.equal("-oControlPath=/tmp/ssh-client-wrapper-%r@%h:%p");
|
|
37
|
+
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
38
|
+
});
|
|
39
|
+
it("should change ControlPath by Environment variable", () => {
|
|
40
|
+
process.env.SSH_CONTROL_PERSIST_DIR = "/tmp";
|
|
41
|
+
const sshOpts = getSshOption(defaultValues);
|
|
42
|
+
expect(sshOpts).to.be.an("array");
|
|
43
|
+
expect(sshOpts).to.have.lengthOf(4);
|
|
44
|
+
expect(sshOpts[0]).to.equal(defaultValues.host);
|
|
45
|
+
expect(sshOpts[1]).to.equal("-oControlMaster=auto");
|
|
46
|
+
expect(sshOpts[2]).to.equal("-oControlPath=/tmp/ssh-client-wrapper-%r@%h:%p");
|
|
47
|
+
expect(sshOpts[3]).to.equal("-oControlPersist=180");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
File without changes
|