Now-a-days, we can see that whole world is moving around Clouds and virtualization. More and more applications are building for managing datacentre servers and other stuff. I have been part of one of such a module. I developed one module for monitoring and managing Linux servers remotely. We used JCraft’s Jsch with Google’s Expect4j for the same. Let’s get some idea about those API in brief.

JSCH

As the website suggests, it is pure implementation of SSH2. It is very easy to use and integrate into your program. It is a fact that it is not well documented. You can read more about JSchfrom its website.

Expect4j

Expect is the kitchen sink of IO control. It supports control of processes and sockets, and a complex method of match multiple patterns at the same time. This is what Google code has to say about Expect4j. When you executes commands on remote machines one after other, your program needs to know when to execute next command. It’s like send your command and wait for execution of the same. Or we can say that wait for the command prompt. Expect4j does similar stuff(as far as I know). It also provides closures for getting complete output log of executed commands. I don’t know if there is some other use of closures.

Now, let’s start with an example. First open up SSH connection on remote machine.

1
2
3
4
5
6
7
8
9
10
11
JSch jsch = new JSch();
Session session = jsch.getSession(username, hostname, port);
session.setPassword(password);
 
Hashtable<String,String> config = new Hashtable<String,String>();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect(60000);
ChannelShell channel = (ChannelShell) session.openChannel("shell");
Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
channel.connect();

You can see that we have opened “shell” channel. That is because we want to execute sequence of commands on linux shell. You can see that Expect4j is initialized from JSCH session.

Now, we will prepare RegX patterns of command prompts of targeted machine. Be careful here because if these are not right then you might end up not executing commands. You can also provide closure provided by Expect4j to get output of your commands. (There might be some other use of it.)

1
2
3
4
5
6
StringBuilder buffer = new StringBuilder();
Closure closure = new Closure() {
            public void run(ExpectState expectState) throws Exception {
                buffer.append(expectState.getBuffer());//string buffer for appending output of executed command
            }
};
1
2
3
4
5
6
7
8
9
10
11
12
String[] linuxPromptRegEx = new String[]{"\\>","#"};
List<Match> lstPattern =  new ArrayList<Match>();
        for (String regexElement : linuxPromptRegEx) {
            try {
                Match mat = new RegExpMatch(regexElement, closure);
                lstPattern.add(mat);
            } catch (MalformedPatternException e) {
                e.printStackTrace();
            } catch(Exception e) {
                e.printStackTrace();
            }
}

You can see that we have defined a closure that appends output of every command executed. We are providing this closure to every command pattern. I have my linux shell prompt working at “/>” and “#”. You can define your prompts as per your linux box.

Now, start executing commands.

1
2
3
4
5
6
7
8
9
10
11
12
13
List<String> lstCmds = new ArrayList<String>();
lstCmds.add("ls");
lstCmds.add("pwd");
lstCmds.add("mkdir testdir");
 
for(String strCmd : lstCmds) {
    int returnVal = expect.expect(objPattern);
    if (returnVal == -2) {
        expect.send(strCommandPattern);
        expect.send("\r");//enter character
    }
}

We have three commands to execute in a single continuous SSH session.  First it expects one of its prompt patterns to match. If right prompt has encountered then send one command over the shell to execute.  Immediately after the command, send an enter character to execute the command. After that again wait for one of your command prompt to occur and then send other command. So, we can see that it send/wait kind of mechanism.

Now, put all together and here is a SSH client that can execute sequence of command on remote linux box. You will need following libraries in your project to execute this test class.

  • expect4j-1.0.jar
  • jakarta-oro.jar
  • jsch-0.1.44.jar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
import org.apache.oro.text.regex.MalformedPatternException;
 
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
 
import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
 
public class SSHClient {
 
    private static final int COMMAND_EXECUTION_SUCCESS_OPCODE = -2;
    private static String ENTER_CHARACTER = "\r";
    private static final int SSH_PORT = 22;
    private List<String> lstCmds = new ArrayList<String>();
    private static String[] linuxPromptRegEx = new String[]{"\\>","#", "~#"};
 
    private Expect4j expect = null;
    private StringBuilder buffer = new StringBuilder();
    private String userName;
    private String password;
    private String host;
 
    /**
     *
     * @param host
     * @param userName
     * @param password
     */
    public SSHClient(String host, String userName, String password) {
        this.host = host;
        this.userName = userName;
        this.password = password;
    }
    /**
     *
     * @param cmdsToExecute
     */
    public String execute(List<String> cmdsToExecute) {
        this.lstCmds = cmdsToExecute;
 
        Closure closure = new Closure() {
            public void run(ExpectState expectState) throws Exception {
                buffer.append(expectState.getBuffer());
            }
        };
        List<Match> lstPattern =  new ArrayList<Match>();
        for (String regexElement : linuxPromptRegEx) {
            try {
                Match mat = new RegExpMatch(regexElement, closure);
                lstPattern.add(mat);
            } catch (MalformedPatternException e) {
                e.printStackTrace();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
 
        try {
            expect = SSH();
            boolean isSuccess = true;
            for(String strCmd : lstCmds) {
                isSuccess = isSuccess(lstPattern,strCmd);
                if (!isSuccess) {
                    isSuccess = isSuccess(lstPattern,strCmd);
                }
            }
 
            checkResult(expect.expect(lstPattern));
        } catch (Exception ex) {
            ex.printStackTrace();
        } finally {
            closeConnection();
        }
        return buffer.toString();
    }
    /**
     *
     * @param objPattern
     * @param strCommandPattern
     * @return
     */
    private boolean isSuccess(List<Match> objPattern,String strCommandPattern) {
        try {
            boolean isFailed = checkResult(expect.expect(objPattern));
 
            if (!isFailed) {
                expect.send(strCommandPattern);
                expect.send(ENTER_CHARACTER);
                return true;
            }
            return false;
        } catch (MalformedPatternException ex) {
            ex.printStackTrace();
            return false;
        } catch (Exception ex) {
            ex.printStackTrace();
            return false;
        }
    }
    /**
     *
     * @param hostname
     * @param username
     * @param password
     * @param port
     * @return
     * @throws Exception
     */
    private Expect4j SSH() throws Exception {
        JSch jsch = new JSch();
        Session session = jsch.getSession(userName, host, SSH_PORT);
        if (password != null) {
            session.setPassword(password);
        }
        Hashtable<String,String> config = new Hashtable<String,String>();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect(60000);
        ChannelShell channel = (ChannelShell) session.openChannel("shell");
        Expect4j expect = new Expect4j(channel.getInputStream(), channel.getOutputStream());
        channel.connect();
        return expect;
    }
    /**
     *
     * @param intRetVal
     * @return
     */
    private boolean checkResult(int intRetVal) {
        if (intRetVal == COMMAND_EXECUTION_SUCCESS_OPCODE) {
            return true;
        }
        return false;
    }
    /**
     *
     */
    private void closeConnection() {
        if (expect!=null) {
            expect.close();
        }
    }
    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        SSHClient ssh = new SSHClient("linux_host", "root", "password");
        List<String> cmdsToExecute = new ArrayList<String>();
        cmdsToExecute.add("ls");
        cmdsToExecute.add("pwd");
        cmdsToExecute.add("mkdir testdir");
        String outputLog = ssh.execute(cmdsToExecute);
        System.out.println(outputLog);
    }
}

If you find any difficulties to execute it, just play around execute command loop and command prompts RegX patterns.

Remote SSH: Using JSCH with Expect4j的更多相关文章

  1. The remote SSH server rejected X11 forwarding request

    两台相同的虚拟机,一台没有错误,一个经常出现警告,内容如下所示: The remote SSH server rejected X11 forwarding request 找了很多方法,最后发现是安 ...

  2. Xshell报错“The remote SSH server rejected X11 forwarding request.”

    Xshell报错“The remote SSH server rejected X11 forwarding request.” 2012年12月17日 ⁄ Linux⁄ 共 218字 ⁄ 字号 小  ...

  3. Xshell 连接虚拟机出现 "The remote SSH server rejected X11 forwarding request"

    1. 描述 虚拟机:VirtualBox Linux: centOS7 解决了 centOS7在VirtualBox中装好后的网络连接问题 后,用 Xshell 连接服务器时出现下面情况: 2. ss ...

  4. 解决 Xshell 连接出现 The remote SSH server rejected X11 forwarding request 问题

    问题描述 使用 Xshell 5 首次连接虚拟机 CentOS 7.6 出现这样的提示: WARNING! The remote SSH server rejected X11 forwarding ...

  5. 解决"The remote SSH server rejected X11 forwarding request"问题

    今天突然想起来好久没有登录我的vps了,于是下载了xshell,填入地址登录后,看到提示"WARNING! The remote SSH server rejected X11 forwar ...

  6. 解决“WARNINGThe remote SSH server rejected X11 forwarding request.“警告

    使用xshell连接服务器时,出现了"WARNING! The remote SSH server rejected X11 forwarding request.",意思是&qu ...

  7. SELINUX设为Disable 影响java SSH工具包Jsch 0.1.49.jar的一个案例

    最近项目中遇到一个典型事件,当RHEL 的SELINUX设为DISABLE时 使用JAVA的Jsch 库调用SSH命令时将随机返回空字符串,我使用的版本是0.1.49,最新版本0.1.51未测试. 关 ...

  8. java控制远程ssh-JSCH(二)

    github: https://github.com/wengyingjian/ssh-java-demo.git 这次找到了一套新的api,叫jsch.网上查了一下,顺便把官网的几个demo给一通拿 ...

  9. VS Code Remote SSH设置

    本文翻译自:5 Steps: Setup VS Code for Remote Development via SSH from Windows to Linux system 5个步骤:设置VS代码 ...

随机推荐

  1. 理解FlumeNG的batchSize和transactionCapacity参数和传输事务的原理 【转】

    基于ThriftSource,MemoryChannel,HdfsSink三个组件,对Flume数据传输的事务进行分析,如果使用的是其他组件,Flume事务具体的处理方式将会不同. Flume的事务处 ...

  2. sql随机查询数据order by newid()

    方法1:最普通的写法,性能慢 ID,name FROM dt_keyword ORDER BY NEWID() 方法2:性能还可以 //先给数据库增加一列ALTER TABLE dt_keyword ...

  3. 常用查找算法(Java)

    常用查找算法(Java) 2018-01-22 1 顺序查找 就是一个一个依次查找 2 二分查找 二分查找(Binary Search)也叫作折半查找. 二分查找有两个要求, 一个是数列有序, 另一个 ...

  4. UnicodeDecodeError: 'ascii' codec can't decode byte 0xa3 in position 1: ordinal not in range(128)

    使用codecs模块 codecs模块能在处理字节流的时候提供很大帮助.你可以用定义的编码来打开文件并且你从文件里读取的内容会被自动转化为Unicode对象. 试试这个: >>> i ...

  5. 【机器学习】K近邻算法——多分类问题

    给定一个训练数据集,对新的输入实例,在训练数据集中找到与该实例最邻近的K个实例,这K个实例的多数属于某个类,就把该类输入实例分为这个类. KNN是通过测量不同特征值之间的距离进行分类.它的的思路是:如 ...

  6. 基于jQuery遮罩图片hover翻转效果

    基于jQuery遮罩图片hover翻转效果.这是一款基于jQuery+css3实现的鼠标经过遮罩图片翻转特效.效果图如下: 在线预览   源码下载 实现的代码. html代码: <div cla ...

  7. java基础篇---文件上传(smartupload组件)

    文件上传几乎是所有网站都具有的功能,用户可以将文件上传到服务器的指定文件夹中,也可以保存在数据库中,本篇主要说明smartupload组件上传. 在讲解smartupload上传前,我们先来看看不使用 ...

  8. 数据库like匹配的实现猜测

    insert into test_fulltext values("王正科技全文") select * from test_fulltext where data like &qu ...

  9. MyEclipse10中配置开发Python所需要的PyDev 绝对靠谱 不忽悠!

    在NLP(自然语言处理)这个领域中,Python具有良好的声誉,于是也想学习一下.首先第一步就是需要在计算机上配置Python环境.由于Python自带的编辑器太简单,使用起来不顺手,于是就考虑在相对 ...

  10. u-boot的配置

    1 sama5d31dk           sama5d3_xplained:SAMA5D3,SYS_USE_NANDFLASH                                    ...