All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nerve.tools.ssh.ShellHandler Maven / Gradle / Ivy

package org.nerve.tools.ssh;

import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.Session;
import expect4j.Closure;
import expect4j.Expect4j;
import expect4j.ExpectState;
import expect4j.matches.EofMatch;
import expect4j.matches.Match;
import expect4j.matches.RegExpMatch;
import expect4j.matches.TimeoutMatch;
import org.nerve.tools.ssh.bean.SshInfo;

import java.util.ArrayList;
import java.util.List;

/**
 * com.zeus.ssh
 * Created by zengxm on 2015/12/10 0010.
 */
public class ShellHandler extends AbstractSessionHandler {

	private ChannelShell channel;
	private Expect4j expect = null;
	private static final long defaultTimeOut = 1000;
	private StringBuffer buffer=new StringBuffer();

	public 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;

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

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

	private boolean responeWithoutCommand = true;        //responde 中是否包含命令本身
	private String currentCommand;  //当前执行的命令
	private String lastResponse;    //最后的一条命令的回复信息

	private List patternList;

	public ShellHandler(SshInfo sshInfo){
		super(sshInfo);
		expect = getExpect();
	}

	public ShellHandler(Session session){
		super(session);
		expect = getExpect();
	}

	public boolean isResponeWithoutCommand() {
		return responeWithoutCommand;
	}

	public ShellHandler setResponeWithoutCommand(boolean responeWithoutCommand) {
		this.responeWithoutCommand = responeWithoutCommand;
		return this;
	}

	public String getCurrentCommand() {
		return currentCommand;
	}

	public String getLastResponse() {
		return lastResponse;
	}

	public String getResponse(){
		return buffer.toString();
	}

	public ShellHandler clean(){
		buffer.setLength(0);
		return this;
	}

	//获得Expect4j对象,该对用可以往SSH发送命令请求
	private Expect4j getExpect() {
		try {
			channel = (ChannelShell) getSession().openChannel("shell");
			channel.setPty(true);
			channel.setEnv("nerve", "hello, I am from nerve");
			Expect4j expect = new Expect4j(channel.getInputStream(), channel
					.getOutputStream());
			channel.connect();

			if(sshInfo != null)
				log.info("open session shell successful on {}@{}:{}", sshInfo.getUser(), sshInfo.getHost(), sshInfo.getPort());

			initExpect();
			return expect;
		} catch (Exception ex) {
			log.error("failed open session shell", ex);
			//ex.printStackTrace();
			throw new RuntimeException("failed open session shell:"+ex.getMessage());
		}
	}

	private void initExpect() throws Exception{
		Closure closure = new Closure(){
			public void run(ExpectState expectState) throws Exception {
				String re = expectState.getBuffer().trim();
				//获取最近执行命令的回复信息
				if(currentCommand != null && re.startsWith(currentCommand)){
					String re2 = re.replace(currentCommand, "");
					if(responeWithoutCommand){
						int index = re2.indexOf("\n");
						if(index <=1)
							re2 = re2.substring(index+1);
					}
					lastResponse = re2;
				}
				buffer.append(re);// buffer is string
				// buffer for appending
				// output of executed
				// command
				expectState.exp_continue();
			}
		};
		patternList = new ArrayList();
		String[] regEx = linuxPromptRegEx;
		if (regEx != null && regEx.length > 0) {
			synchronized (regEx) {
				for (String regexElement : regEx) {// list of regx like, :>, />
					// etc. it is possible
					// command prompts of your
					// remote machine
					try {
						RegExpMatch mat = new RegExpMatch(regexElement, closure);
						patternList.add(mat);
					} catch (Exception e) {
						throw e;
					}
				}
				patternList.add(new EofMatch(new Closure() { // should cause
					// entire page to be
					// collected
					public void run(ExpectState state) {
					}
				}));
				patternList.add(new TimeoutMatch(defaultTimeOut, new Closure() {
					public void run(ExpectState state) {
					}
				}));
			}
		}
	}

	@Override
	public void disconnect() {
		super.disconnect();
		if(expect != null)
			expect.close();
		if(channel != null)
			channel.disconnect();
	}

	/**
	 * 执行命令,只有全部都执行成功后,才返回true
	 * @param commands      待执行的命令
	 * @return              true if all commands is done
	 */
	public boolean exec(String... commands){
		//如果expect返回为0,说明登入没有成功
		if(expect==null){
			return false;
		}

		log.debug("----------Running commands are listed as follows:----------");
		for(String command:commands){
			log.debug(command);
		}
		log.debug("----------End----------");

		try {
			boolean isSuccess = true;
			for (String cmd : commands){
				isSuccess = isSuccess(patternList, cmd);
			}
			//防止最后一个命令执行不了
			isSuccess = !checkResult(expect.expect(patternList));
			//找不到错误信息标示成功
			String response=buffer.toString().toLowerCase();
			for(String msg:errorMsg){
				if(response.indexOf(msg)>-1){
					return false;
				}
			}
			return isSuccess;
		} catch (Exception ex) {
			ex.printStackTrace();
			return false;
		}
	}

	//检查执行是否成功
	private boolean isSuccess(List objPattern, String strCommandPattern) {
		try {
			boolean isFailed = checkResult(expect.expect(objPattern));
			if (!isFailed) {
				currentCommand = strCommandPattern;
				expect.send(strCommandPattern+"\r");
				return true;
			}
		} catch (Exception ex) {
			log.error("error on call isSuccess()", ex);
		}
		return false;
	}

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




© 2015 - 2024 Weber Informatics LLC | Privacy Policy