CacheCloud详解(二)---------- SSH-2协议工具包

SSH-2协议工具包:

CacheCloud平台提供了对redis集群的集中化管理、运维、监控等功能,但是CacheCloud是如何对机器进行监控和维护的呢?是
如何获得redis所在服务器的信息呢?

通过查看源代码,发现平台引入了SSH-2协议的工具包:ganymed-ssh2,这个工具包提供了java连接linux服务器的功能,通过这个工具包就可以在服务器上面执行应用逻辑

	<dependency>
        <groupId>ch.ethz.ganymed</groupId>
        <artifactId>ganymed-ssh2</artifactId>
        <version>build210</version>
    </dependency>

CacheCloud中用于SSH-2连接的类主要包含了以下几个:

  • SSHTemplate:提供了SSH操作的模板,包含了创建SSH连接、执行SSHCallback回调、获取结果、解析结果和关闭连接的功能
  • SSHSession:根据SSH连接获取session会话;执行linux命令,获得执行结果;上传文件到远程服务器
  • Result:SSH结果包装类
  • SSHCallback:SSH执行命令回调
  • LineProcessor:结果解析器
  • DefaultLineProcessor:默认的结果解析器
  • SSHUtil:工具类,包含了收集机器信息、传输文件到远程服务器、查看端口是否被占用、获得ssh端口和获取cpu状况
SSHSession:
获取SSH连接:
     /**
	 * 通过回调执行命令
	 * @param ip
	 * @param port
	 * @param username
	 * @param password
	 * @param callback 可以使用Session执行多个命令
	 * @throws SSHException 
	 */
    public Result execute(String ip, int port, String username, String password, 
    		SSHCallback callback) throws SSHException{
        Connection conn = null;
        try {
            conn = getConnection(ip, port, username, password);
            return callback.call(new SSHSession(conn, ip+":"+port));
        } catch (Exception e) {
            throw new SSHException("SSH err: " + e.getMessage(), e);
        } finally {
        	close(conn);
        }
    }
    
	 /**
   	 * 执行命令并返回结果,可以执行多次
   	 * @param cmd 执行命令
   	 * @param lineProcessor 回调消息解析器
   	 * @return 如果lineProcessor不为null,那么永远返回Result.true
   	 */
   	public Result executeCommand(String cmd, LineProcessor lineProcessor, int timoutMillis) {
   		Session session = null;
   		try {
   			//通过SSH连接打开session会话
   			session = conn.openSession();
   			return executeCommand(session, cmd, timoutMillis, lineProcessor);
		} catch (Exception e) {
			logger.error("execute ip:"+conn.getHostname()+" cmd:"+cmd, e);
			return new Result(e);
		} finally {
			close(session);
		}
   	}
执行命令:
		public Result executeCommand(final Session session, final String cmd, 
    			final int timoutMillis, final LineProcessor lineProcessor) throws Exception{
    		//通过线程池的方式异步执行linux命令
    		Future<Result> future = taskPool.submit(new Callable<Result>() {
				public Result call() throws Exception {
				    //具体执行linux命令的代码
					session.execCommand(cmd);
					//如果客户端需要进行行处理,则直接进行回调
					if(lineProcessor != null) {
						processStream(session.getStdout(), lineProcessor);
					} else {
						//获取标准输出
						String rst = getResult(session.getStdout());
						if(rst != null) {
							return new Result(true, rst);
						}
						//返回为null代表可能有异常,需要检测标准错误输出,以便记录日志
						Result errResult = tryLogError(session.getStderr(), cmd);
						if(errResult != null) {
							return errResult;
						}
					}
					return new Result(true, null);
				}
			});
    		Result rst = null;
    		try {
    			//当timeoutMillis毫秒还没有返回结果,则取消执行,否则返回结果,不过Future只能确定线程执行完,
    			//不能确定执行是否成功,因为Future只提供了isDone()方法确定线程执行完毕
    			rst = future.get(timoutMillis, TimeUnit.MILLISECONDS);
    			future.cancel(true);
    		} catch (TimeoutException e) {
    			logger.error("exec ip:{} {} timeout:{}", conn.getHostname(), cmd, timoutMillis);
    			throw new SSHException(e);
    		}
    		return rst;
    	}
上传文件:
		/**
    	 * Copy a set of local files to a remote directory, uses the specified mode when
    	 * creating the file on the remote side.
    	 * @param localFiles
    	 *            Path and name of local file.
    	 * @param remoteFiles
    	 *            name of remote file.
    	 * @param remoteTargetDirectory
    	 *            Remote target directory. Use an empty string to specify the default directory.
    	 * @param mode
    	 *            a four digit string (e.g., 0644, see "man chmod", "man open")
    	 * @throws IOException
    	 */
    	public Result scp(String[] localFiles, String[] remoteFiles, String remoteTargetDirectory, String mode) {
    		try {
    			//通过连接创建SCP客户端,使用put方法将文件上传到远程服务器
    			SCPClient client = conn.createSCPClient();
				client.put(localFiles, remoteFiles, remoteTargetDirectory, mode);
				return new Result(true);
			} catch (Exception e) {
				logger.error("scp local="+Arrays.toString(localFiles)+" to "+
						remoteTargetDirectory+" remote="+Arrays.toString(remoteFiles)+" err", e);
				return new Result(e);
			}
    	}
SSHCallback:
 	/**
     *	执行命令回调
     */
    public interface SSHCallback{
    	/**
    	 * 执行回调
    	 * @param session
    	 */
    	Result call(SSHSession session);
    }
	/**
     * 从流中直接解析数据
     */
	  public static interface LineProcessor{
		/**
		 * 处理行
		 * @param line  内容
		 * @param lineNum   行号,从1开始
		 * @throws Exception
		 */
		void process(String line, int lineNum) throws Exception;
		
		/**
		 * 所有的行处理完毕回调该方法
		 */
		void finish();
	}
	//默认的数据解析器
	public static abstract class DefaultLineProcessor implements LineProcessor{
		public void finish() {}
	}

大致整理一下调用逻辑:

CacheCloud详解(二)---------- SSH-2协议工具包_第1张图片
逻辑有点复杂,需要大家耐心去看,多看几遍代码就懂了,哈哈!

如果有不懂之处,欢迎关注微信公众号:代码小栈,期待为您解决更多难题

CacheCloud详解(二)---------- SSH-2协议工具包_第2张图片

你可能感兴趣的:(cachecloud,redis)