方案一:脚本所在服务器安装一个客户端,也就是自己写的一个小程序,本地通过端口调目标服务器的程序,然后程序调本机上的shell脚本!
优点:通过端口调用,用户不用暴露服务器的账号密码,安全性高
缺点:我们需要一直维护这个客户端程序,而且每接入一台服务器,都得安装该客户端,另外非常考验客户端程序的健壮性。
方案二:本地直接通过IP,服务器账号密码调远程服务器的shell脚本
优点:代码易开发,扩展时只用扩展服务端代码即可
缺点:用户服务器的账号密码会暴露给服务端,密码安全问题
把每种方案的优缺点汇报给leader,leader说:按第二种来吧
来吧!!开干,废话不多说,直接上代码:
导入程序所需的软件包:
<dependency>
<groupId>org.jvnet.hudson</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>build210-hudson-1</version>
</dependency>
程序涉及的demo:
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import ch.ethz.ssh2.ChannelCondition;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.Session;
import ch.ethz.ssh2.StreamGobbler;
//java项目www.fhadmin.org
public class RemoteShellExecutor {
private Connection conn;
/** 远程机器IP */
private String ip;
/** 用户名 */
private String osUsername;
/** 密码 */
private String password;
private String charset = Charset.defaultCharset().toString();
private final String GET_SHELL_PID = "ps -ef | grep '%s' | grep -v grep |awk '{print $2}'";
private final String KILL_SHELL_PID = "kill -15 %s";
private static final int TIME_OUT = 1000 * 5 * 60;
/**
* 构造函数
* @param ip
* @param usr
* @param pasword
*/
public RemoteShellExecutor(String ip, String usr, String pasword) {
this.ip = ip;
this.osUsername = usr;
this.password = pasword;
}
/**
* 登录
* @return
* @throws IOException
*/
private boolean login() throws IOException {
conn = new Connection(ip);
conn.connect();
return conn.authenticateWithPassword(osUsername, password);
}
/**java项目www.fhadmin.org
* 执行脚本
*
* @param cmds
* @return
* @throws Exception
*/
public ExecuteResultVO exec(String cmds) throws Exception {
InputStream stdOut = null;
InputStream stdErr = null;
ExecuteResultVO executeResultVO = new ExecuteResultVO();
String outStr = "";
String outErr = "";
int ret = -1;
try {
if (login()) {
// Open a new {@link Session} on this connection
Session session = conn.openSession();
// Execute a command on the remote machine.
session.execCommand(cmds);
stdOut = new StreamGobbler(session.getStdout());
outStr = processStream(stdOut, charset);
stdErr = new StreamGobbler(session.getStderr());
outErr = processStream(stdErr, charset);
session.waitForCondition(ChannelCondition.EXIT_STATUS, TIME_OUT);
System.out.println("outStr=" + outStr);
System.out.println("outErr=" + outErr);
ret = session.getExitStatus();
executeResultVO.setOutStr(outStr);
executeResultVO.setOutErr(outErr);
} else {
throw new Exception("登录远程机器失败" + ip); // 自定义异常类 实现略
}
} finally {
if (conn != null) {
conn.close();
}
IOUtils.closeQuietly(stdOut);
IOUtils.closeQuietly(stdErr);
}
return ret;
}
/**java项目www.fhadmin.org
* @param in
* @param charset
* @return
* @throws IOException
* @throws UnsupportedEncodingException
*/
private String processStream(InputStream in, String charset) throws Exception {
byte[] buf = new byte[1024];
StringBuilder sb = new StringBuilder();
int len = 0;
while ((len=in.read(buf)) != -1) {
sb.append(new String(buf,0,len, charset));
}
return sb.toString();
}
public static void main(String args[]) throws Exception {
//调远程shell
RemoteShellExecutor executor = new RemoteShellExecutor("192.168.234.123", "root", "beebank");
System.out.println(executor.exec("sh /data/checkMysql.sh"));
//获取远程shell 进程 pid
ExecuteResultVO executeResultVO = executor.exec(String.format(GET_SHELL_PID,"sh /data/checkMysql.sh"));
//杀掉shell进程
ExecuteResultVO executeResultVO1 = executor.exec(String.format(KILL_SHELL_PID ,executeResultVO.getOutStr()));
}
public class ExecuteResultVO<T>{
private String outStr;
private String outErr;
//省略get set
}
}