SSH - npm似乎打破了ssh非pty shell

时间:2017-05-15 06:34:28

标签: node.js shell ssh npm pty

我正在开发一个库/工具,让用户通过SSH执行任意命令。总的来说,这个lib /工具将作为软件部署工具,需要访问远程机器来执行几个命令(cd,mkdir,git ..., npm install ,scp等)。

虽然它基本上可以通过SSH执行远程命令,但似乎每次执行命令npm install时,SSH连接都会终止。我无法分辨是什么导致了这种情况,但这个非常简单的Node.js脚本可以证明它:

const spawn = require('child_process').spawn;
const bat = spawn('ssh', ['-T', '-oRequestTTY=no', '-oBatchMode=yes', 'user@host']);

bat.stdout.on('data', (data) => console.log('STDOUT: ' + data.toString()));
bat.stderr.on('data', (data) => console.log('STDERR: ' + data.toString()));
bat.on('exit', (code) => console.log(`Child exited with code ${code}`));

setTimeout(() => {
    bat.stdin.write('pwd -P\n');
    bat.stdin.write('cd someDir\n');
    bat.stdin.write('npm install\n');

    setTimeout(() => bat.stdin.write('pwd -P\n'), 2000);
}, 2000);

这将在npm install之后中断/终止分叉的SSH进程,因此延迟的pwd -P也将失败。删除npm install命令将使SSH进程保持不变,直到用户终止该应用程序。

当我使用c库libssh时遇到了这个问题,我遇到了同样的问题,尽管我没有注意到npm install命令似乎实际上触发了问题。请参阅此相关帖子:Channel in libssh gets closed for no obvious reason

我发现的是:
 1.我使用的是非pty SSH shell  2. libssh数据包级调试输出显示服务器在连接关闭之前发送的数据包98  3.根据RFC,数据包98为SSH_MSG_CHANNEL_REQUEST,其中 也可用于请求 pty

所以我的假设是,我正在通过SSH处理非pty shell,并且npm程序中的某些内容直接或间接导致服务器端请求pty,这是无法处理的通过我正在处理的非pty shell,因此,SSH连接在协议级别上关闭。

现在我的问题是,是什么导致这种情况,有没有办法摆脱这个问题?

可能会在29日更新

实际上,我能够进一步调查此问题。我开始编辑npm-cli.js并注释掉所有内容,然后逐步取消注释行,以查看将触发上述行为的内容。 起初,似乎通过npmlog包含的集合阻止模块导致了这个问题,但是在 index.js:4 (也就是在 index.js:4 中注释了集合阻塞的实际代码之后只有stream._handle.setBlocking(blocking)),不良行为仍然会发生,这让我感到困惑。进一步的实验表明,实际上process.stdout的单个部分导致了整个问题。

为了验证,我做了以下事情:

  • 在npm-cli.js中注释掉第22-94行。现在执行npm install基本上什么都不做。另外,运行上面的示例程序不会出错。
  • 将以下代码添加到 npm-cli.js:19 if (process.stdout) ;。这基本上什么都不做,但如果执行上述测试程序,则会导致再次发生错误。
  • 执行相反的测试并将if (process.stdout) ;更改为if (process) ; - 测试程序现在将再次运行而不会出错。

所以基本上可以改变上面描述错误的Node.js测试程序,以便调用一个简单的oneline脚本代替npm install,这会导致同样的错误:

const spawn = require('child_process').spawn;
const bat = spawn('ssh', ['user@host']);

setTimeout(() => {
    bat.stdin.write('node test.js\n');        // this breaks it

    setTimeout(() => bat.stdin.write('pwd -P\n'), 2000);
}, 2000);

test.js包含:

if (process.stdout) ;  // only this line

我不知道进程全局对象是如何构造的,或者这里发生了什么,但是Node.js' process / process.stdout对象以某种方式破坏了SSH连接。因此,我认为这不是npm的实际问题,只是间接的。

有人可以帮忙解释一下吗?

0 个答案:

没有答案