1. 程式人生 > >java 通過 ssh 執行 shell 命令

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 %[email protected]%s:%s", user, ip, port)); jsch = new JSch(); addIdentity(privateKey, passphrase); ; session(ip, user, psw, port); expect(); log.debug(String.format("Logging to %[email protected]%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>