nestjs+ssh2shell

242 阅读1分钟

背景

记录一个JavaScript的全栈项目,包括服务端及前端页面。前后端分别采用了umijs和nestjs框架。在服务端,涉及到远端登入其他服务器的功能,同时在登入到其他服务器后,需要进行一些shell操作。

问题

关于js远端登入服务器的功能,一开始采用了ssh2这个库,简单实用。 具体代码如下

import { Client } from 'ssh2';
export function sshCommand(login: ILogin): Promise<any> {
    const client = new Client();
    return new Promise((resolve) => {
        client.connect(login)
            .on('ready', (...args) => {
                // shell命令
                client.exec('docker ps', (e, ch) => {
                    ch.once('data', (chunk) => {
                        // 命令获取的内容
                        resolve(chunk.toString());
                    })
                })
            })
            .on('close', () => {
                console.log('connection closed')
            })
            .on('error', (e) => {
                console.log(`connection error:${e}`)
            })
    });
}

export interface ILogin {
    host: string,
    password: string,
    username: string,
    port: number
}

在实际使用中,会存在如下问题:

  • 命令只能够单个执行
  • ch.once回调函数执行的时机存在问题,当chunk很长时,每次返回的内容不全,且长度不一
  • 无法实现命令交互,例如scp拷贝是时,无法模拟控制台输入passwd的行为

解决

尝试了很久没有解决,在不经意间找到了那根救命稻草,ssh2shell库,传送门www.npmjs.com/package/ssh…

代码如下


export function transmitFile(fileName: string, destIP: string, login: ILogin, password: string) {
    return new Promise((resolve) => {
        const obj = {
            server: login,  // 登入服务器
            commands: [
                fileName    // 操作命令 eg:scp...
            ],
            /**
             * 命令执行过程
             * @param command 
             * @param response 终端返回的内容
             * @param sshObj 
             * @param stream 
             */
            onCommandProcessing: function (command, response, sshObj, stream) {
                // 终端打印的内容
                // 转化为小写,这里是个坑,不同的服务器可能返回值不一样
                // 本人遇到过Password和password这两种
                if (response.toLocaleLowerCase().indexOf('password')) {
                    // 检测到当前需要输入目的端的密码
                    // 回车不能少
                    stream.write(`${password}\n`);
                }
            }
        };
        const ssh = new ssh2shell(obj);
        ssh.connect();
    });
}

同时,上述1、2问题也能通过ssh2shell这个库来解决,唯一缺点就是找到的相关内容,都是英文的,阅读起来增加了一些困难。好在,npm安装后,可以参考test去使用。

后记

当前也只是解决了眼前的问题,不知道后面的维护过程中是否会产生新的问题,但是办法总比困难多。