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 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 || 1;
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 ControlPersist = Number.isInteger(hostInfo.ControlPersist) && hostInfo.ControlPersist >= 0 ? hostInfo.ControlPersist : "180";
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("-oControlPath=~/.ssh/ssh-client-wrapper-%r@%h:%p");
185
- args.push(`-oControlPersist=${ControlPersist}`);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ssh-client-wrapper",
3
- "version": "2.5.0",
3
+ "version": "2.6.1",
4
4
  "description": "wrapper library for open ssh client and rsync",
5
5
  "keywords": [
6
6
  "ssh",
@@ -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