java 通过 ssh 执行 shell 命令


public abstract class Shell implements AutoCloseable{
    abstract boolean executeCommands(String... commands);
    abstract String getResponse();
    public abstract void close();
}

class SSH2Shell extends Shell{

    private static Logger      log                              = LoggerFactory.getLogger(SSH2Shell.class);

    private static final int   DEFAULT_TIME_OUT                 = 1000;
    private static final int   CONNECT_TIME_OUT                 = 3000;
    private static final int   COMMAND_EXECUTION_SUCCESS_OPCODE = -2;

    public static final String BACKSLASH_R                      = "\r";
    public static final String BACKSLASH_N                      = "\n";
    public static final String COLON_CHAR                       = ":";
    public static String       ENTER_CHARACTER                  = BACKSLASH_R;

    private Session            session;
    private ChannelShell       channel;
    private Expect4j           expect                           = null;
    private JSch               jsch;
    private StringBuffer       buffer  ;

    // Threaded session variables
    private boolean closed = false;

    // 正则匹配,用于处理服务器返回的结果
    public static String[]     linuxPromptRegEx                 = new String[] { "~]$", "~]#", "~#", "#", ":~#", "/$", ">" };

    public static String[]     errorMsg                         = new String[] { "could not acquire the config lock " };

    /**
     * 利用JSch包实现远程主机SHELL命令执行, 链接远程主机
     * 
     * @param ip 主机IP
     * @param user 主机登陆用户名
     * @param psw 主机登陆密码
     * @param port 主机ssh2登陆端口,如果取默认值,传-1
     * @param privateKey 密钥文件路径
     * @param passphrase 密钥的密码
     */
    SSH2Shell(String ip, String user, String psw, int port, String privateKey, String passphrase) {
        buffer = new StringBuffer();
        connect(ip, user, psw, port, privateKey, passphrase);
    }

    /**
     * 利用JSch包实现远程主机SHELL命令执行, 链接远程主机 获得Expect4j对象,该对用可以往SSH发送命令请求
     * 
     * @param ip 主机IP
     * @param user 主机登陆用户名
     * @param psw 主机登陆密码
     * @param port 主机ssh2登陆端口,如果取默认值,传-1
     * @param privateKey 密钥文件路径
     * @param passphrase 密钥的密码
     */
    void connect(String ip, String user, String psw, int port, String privateKey, String passphrase) {
        log.info("---------- connect ssh ----------");
        try {
            log.debug(String.format("Start logging to %s@%s:%s", user, ip, port));
            jsch = new JSch();
            addIdentity(privateKey, passphrase);
            ;
            session(ip, user, psw, port);
            expect();
            log.debug(String.format("Logging to %s@%s:%s successfully!", user, ip, port));
        } catch (Exception ex) {
            expect = null;
            log.error("Connect to " + ip + ":" + port + "failed,please check your username and password!");
        }
    }

    /**
     * 执行配置命令
     * 
     * @param commands 要执行的命令,为字符数组
     * @return 执行是否成功
     */
     boolean executeCommands(String... commands) {
        // 如果expect返回为0,说明登入没有成功
        if (expect == null) {
            return false;
        }

        if (log.isDebugEnabled()) {
            log.debug("----------Running commands are listed as follows:----------");
            log.debug(Arrays.toString(commands));
            log.debug("----------End----------");
        }

        try {
            List<Match> lstPattern = lstPattern();
            boolean isSuccess = true;
            for (String strCmd : commands) {
                isSuccess = executeCommand(lstPattern, strCmd);
            }
            // 防止最后一个命令执行不了
            isSuccess = !checkResult(expect.expect(lstPattern));

            // 找不到错误信息标示成功
            String response = buffer.toString().toLowerCase();
            for (String msg : errorMsg) {
                if (response.indexOf(msg) > -1) {
                    return false;
                }
            }

            return isSuccess;
        } catch (Exception ex) {
            log.error(ex.getLocalizedMessage(), ex);
            return false;
        }
    }

    /**
     * 关闭SSH远程连接
     */
    protected void disconnect() {

        if (expect != null) {
            expect.close();
        }
        if (channel != null) {
            channel.disconnect();
        }
        if (session != null) {
            session.disconnect();
        }
        log.info("---------- disconnect ssh ----------");
    }

    @Override
    public void close() {
        if (!this.closed) {
            disconnect();
            this.closed = true;
        }
    }

    /**
     * 获取服务器返回的信息
     * 
     * @return 服务端的执行结果
     */
    public String getResponse() {
        return buffer.toString();
    }

    private void expect() throws JSchException, IOException {
        channel = (ChannelShell) session.openChannel("shell");
        expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
        channel.connect(CONNECT_TIME_OUT);
    }

    private void session(String ip, String user, String psw, int port) throws JSchException {
        if (port <= 0) {
            session = jsch.getSession(user, ip);
        } else {
            session = jsch.getSession(user, ip, port);
        }

        if (session == null) {
            throw new JSchException("Jsch session is null");
        }
        session.setPassword(psw);
        Hashtable<String, String> config = new Hashtable<String, String>();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        localUserInfo ui = new localUserInfo();
        session.setUserInfo(ui);
        session.connect();
    }

    /**
     * 设置ssh 免密登陆
     * 
     * @param jsch
     * @param privateKey
     * @param passphrase
     * @throws JSchException
     */
    private void addIdentity(String privateKey, String passphrase) throws JSchException {
        if (StringUtils.isBlank(privateKey)) {
            return ;
        }

        if (passphrase != null && "".equals(passphrase)) {
            //设置带口令的密钥
            jsch.addIdentity(privateKey, passphrase);
        } else {
            //设置不带口令的密钥
            jsch.addIdentity(privateKey);
        }
    }

    /**
     * @return
     * @throws MalformedPatternException
     */
    private List<Match> lstPattern() throws MalformedPatternException {
        List<Match> lstPattern = new ArrayList<Match>();
        String[] regEx = linuxPromptRegEx;
        if (regEx != null && regEx.length > 0) {
            synchronized (regEx) {
                // list of regx like, :>, />
                // etc. it is possible
                // command prompts of your
                // remote machine
                for (String regexElement : regEx) {
                    RegExpMatch mat = new RegExpMatch(regexElement, x -> {
                        buffer.append(x.getBuffer());
                        x.exp_continue();
                    });
                    lstPattern.add(mat);
                }
                lstPattern.add(new EofMatch(x -> {
                }));
                lstPattern.add(new TimeoutMatch(DEFAULT_TIME_OUT, x -> {
                }));
            }
        }
        return lstPattern;
    }

    // 检查执行是否成功
    private boolean executeCommand(List<Match> objPattern, String strCommandPattern) {
        try {
            boolean isFailed = checkResult(expect.expect(objPattern));
            if (!isFailed) {
                expect.send(strCommandPattern);
                expect.send("\r");
                return true;
            }
            return false;
        } catch (MalformedPatternException ex) {
            return false;
        } catch (Exception ex) {
            return false;
        }
    }

    // 检查执行返回的状态
    private boolean checkResult(int intRetVal) {
        if (intRetVal == COMMAND_EXECUTION_SUCCESS_OPCODE) {
            return true;
        }
        return false;
    }

    // 登入SSH时的控制信息
    // 设置不提示输入密码、不显示登入信息等
    private static class localUserInfo implements UserInfo {
        String passwd;

        public String getPassword() {
            return passwd;
        }

        public boolean promptYesNo(String str) {
            return true;
        }

        public String getPassphrase() {
            return null;
        }

        public boolean promptPassphrase(String message) {
            return true;
        }

        public boolean promptPassword(String message) {
            return true;
        }

        public void showMessage(String message) {

        }
    }

}

依赖

<dependency>
    <groupId>com.github.cverges.expect4j</groupId>
    <artifactId>expect4j</artifactId>
    <version>1.6</version>
</dependency>
<dependency>
    <groupId>com.jcraft</groupId>
    <artifactId>jsch</artifactId>
    <version>0.1.54</version>
</dependency>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值