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功能邏輯
邏輯有點複雜,需要大家耐心去看,多看幾遍代碼就懂了,哈哈!

如果有不懂之處,歡迎關注微信公衆號:代碼小棧,期待爲您解決更多難題

微信公衆號:代碼小棧

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章