可能是巧合吧,近期在开发过程中总是会遇到多层跳板机执行远程命令的场景。之前通过shell执行的情况,发现ssh命令存在一个参数-J
可以支持多层跳板机,具体可以参考之前的一篇文章——ssh多层跳板机解决方法。但是当Java项目尝试去使用ssh执行远程命令时,发现无论是ganymed-ssh-2还是jsch都没有提供相应参数。
实现方式
经过一番搜索,恰巧在jsch官网找到JumpHost的示例,感觉实现方式大开眼界。原理如下图,假设需要通过A、B、C连接D服务器:
代码
由于官网的demo代码比较啰嗦。于是简化了demo代码,写了一个自己的工具类。
自己抽出来的工具类
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
| import com.jcraft.jsch.ChannelExec; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session;
import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Optional; import java.util.function.BiConsumer;
public class SshUtils {
public static void execute(List<SshHost> sshHosts, String command, BiConsumer<InputStream, InputStream> callback) { try { JSch jsch = new JSch(); jsch.addIdentity("~/.ssh/id_rsa"); Session[] sessions = new Session[sshHosts.size()]; Session session = null;
for (int i = 0; i < sshHosts.size(); i++) { SshHost sshHost = sshHosts.get(i); if (i == 0) { sessions[i] = session = jsch.getSession(sshHost.user, sshHost.host, sshHost.port); } else { int assignedPort = session.setPortForwardingL(0, sshHost.host, sshHost.port); sessions[i] = session = jsch.getSession(sshHost.user, "127.0.0.1", assignedPort); } session.setConfig("StrictHostKeyChecking", "no"); session.connect(); }
ChannelExec channel = (ChannelExec)session.openChannel("exec"); channel.setCommand(command); channel.connect(); callback.accept(channel.getInputStream(), channel.getErrStream());
for (int i = sessions.length - 1; i >= 0; i--) { sessions[i].disconnect(); } } catch (JSchException | IOException e) { e.printStackTrace(); } }
public static class SshHost { String user; String host; Integer port;
public SshHost(String user, String host) { this(user, host, 22); }
public SshHost(String user, String host, Integer port) { this.user = user; this.host = host; this.port = Optional.ofNullable(port).orElse(22); } } }
|
工具类使用demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class SshUtilsTest {
@Test public void execute() { List<SshUtils.SshHost> sshHosts = new ArrayList<>(); sshHosts.add(new SshUtils.SshHost("root", "172.16.2.3", 22)); sshHosts.add(new SshUtils.SshHost("root", "10.3.2.123", 22)); sshHosts.add(new SshUtils.SshHost("root", "10.1.6.107", 22)); SshUtils.execute(sshHosts, "ls -l", (stdout, stderr) -> { BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(stdout)); String line; try { while ((line = bufferedReader.readLine()) != null) { System.out.println(line); } } catch (IOException e) { e.printStackTrace(); } }); } }
|
参考
[1] JSch - Examples - JumpHosts.java