<dependency>
<groupId>ch.ethz.ganymed</groupId>
<artifactId>ganymed-ssh2</artifactId>
<version>build210</version>
</dependency>
/**
* <p>Title: abstract service</p>
* <p>Author: lehoon</p>
* <p>Date: 2022/2/28 16:48</p>
*/
@Slf4j
public abstract class BtpAbstractService {
protected String deployPath;
protected String deployBasePath;
//service operate request
protected BtpDeployServiceBaseEntity serviceBaseEntity;
public BtpAbstractService(BtpDeployServiceBaseEntity serviceBaseEntity) {
this.serviceBaseEntity = serviceBaseEntity;
}
protected boolean isDeployBasePathEnvEmpty() {
deployBasePath = StringUtils.trimToEmpty(getDeployBasePath());
return StringUtils.isBlank(deployBasePath);
}
protected String getDeployBasePath() {
return getEnvByName(BtpDeployNodeEnvType.BTP_DEPLOY_NODE_ENV_TYPE_DEPLOY_HOMEPATH.getValue());
}
protected String getEnvByName(String name) {
if (serviceBaseEntity == null || CollectionUtil.isEmpty(serviceBaseEntity.getEnvMap())) return null;
if (serviceBaseEntity.getEnvMap().contAInsKey(name)) return serviceBaseEntity.getEnvMap().get(name).getEnvValue();
return null;
}
protected void updateDeployPath() {
deployPath = String.format("%s/%s", fixFsFilePath(deployBasePath), serviceBaseEntity.getServiceId());
}
protected boolean checkNod.NETState() {
return TcpHelper.isRemoteAlive(serviceBaseEntity.getNodeHost(), serviceBaseEntity.getNodePort());
}
protected String shellDisableEchoCmd() {
return " >> /dev/null 2>&1";
}
protected void sleepCmd() {
sleep(500);
}
protected void sleep3() {
sleep(2000);
}
protected void sleep5() {
sleep(5000);
}
protected void sleep(int timeout) {
try {
Thread.sleep(timeout);
} catch (InterruptedException e) {
}
}
protected String fixFsFilePath(String path) {
if (path == null || path.length() == 0) return "";
if (!path.endsWith("/")) return path;
return path.substring(0, path.length() - 1);
}
protected boolean isDeployBasePathValid() {
return deployBasePath != null && deployBasePath.startsWith("/");
}
abstract protected void preCheck() throws BtpDeployException;
abstract protected void nextCheck() throws BtpDeployException;
abstract protected void process() throws BtpDeployException;
abstract protected void rollBack() throws BtpDeployException;
}
/**
* <p>Title: ssh 操作</p>
* <p>Description: </p>
* <p>Author: lehoon</p>
* <p>Date: 2022/1/20 15:38</p>
*/
@Slf4j
public abstract class BtpAbstractSSHService extends BtpAbstractService {
//ssh connection
protected Connection connection = null;
public BtpAbstractSSHService(BtpDeployServiceBaseEntity serviceBaseEntity) {
super(serviceBaseEntity);
}
public void service() throws BtpDeployException {
preCheck();
try {
login(1000);
} catch (BtpDeployException e) {
log.error("登陆远程服务器失败. ", e);
throw e;
}
try {
nextCheck();
sleep3();
process();
disConnect();
} catch (BtpDeployException e) {
log.error("部署服务操作失败, 错误信息,", e);
rollBack();
disConnect();
throw e;
} finally {
disConnect();
}
}
public void disConnect() {
if (connection == null) return;
connection.close();
connection = null;
}
/**
* 登陆远程服务器
* @param timeout
* @throws Exception
*/
public void login(int timeout) throws BtpDeployException {
connection = new Connection(serviceBaseEntity.getNodeHost(), serviceBaseEntity.getNodePort());
try {
connection.connect(null, timeout, 0);
boolean isAuthenticate = connection.authenticateWithPassword(serviceBaseEntity.getUserName(), serviceBaseEntity.getPassword());
if (!isAuthenticate) {
throw new BtpDeployException("用户名密码错误,登陆失败");
}
} catch (IOException e) {
log.error("登陆远程服务器失败,", e);
if (e.getCause().getMessage().indexOf("method password not supported") != -1) {
throw new BtpDeployException("远程服务器不支持密码认证, 请修改ssh配置文件");
}
throw new BtpDeployException("登陆远程服务器失败, 请检查原因");
} catch (Exception e){
throw new BtpDeployException("登陆远程服务器失败, 请检查原因");
}
}
private void checkConnectState() throws IOException {
if (connection == null) throw new IOException("未与服务器建立连接, 不能执行命令.");
if (!connection.isAuthenticationComplete()) throw new IOException("与服务器连接认证未通过, 不能执行命令.");
}
private String readCmdResult(InputStream inputStream) {
StringBuilder result = new StringBuilder(1024);
try {
InputStream stdout = new StreamGobbler(inputStream);
BufferedReader br = new BufferedReader(new InputStreamReader(stdout));
String cmdResLine = null;
while (true) {
cmdResLine = br.readLine();
if (cmdResLine == null) {
break;
}
result.Append(cmdResLine);
}
} catch (IOException e) {
log.error("读取远程服务器shell指令结果失败, ", e);
}
return result.toString();
}
public boolean executeCmd(String cmd) throws BtpDeploySSHExecException {
try {
return execute1(cmd);
} catch (Exception e) {
log.error(e.getMessage());
throw new BtpDeploySSHExecException(e.getMessage());
}
}
private Session openSession() throws Exception {
checkConnectState();
try {
return connection.openSession();
} catch (Exception e) {
e.printStackTrace();
log.error(e.getMessage());
throw new Exception("打开终端执行环境会话失败,执行命令失败.");
}
}
/**
* 执行命令
* @param cmd
* @return
* @throws IOException
*/
public String execute(String cmd) throws Exception {
sleepCmd();
Session session = openSession();
preHandleSession(session);
session.execCommand(cmd);
String result = readCmdResult(session.getStdout());
log.info("执行命令execute[{}],返回结果为[{}]", cmd, result);
session.close();
return result;
}
public boolean execute1(String cmd) throws Exception {
sleepCmd();
Session session = openSession();
preHandleSession(session);
session.execCommand(cmd);
String result = readCmdResult(session.getStdout());
log.info("执行命令execute1[{}],返回结果为[{}]", cmd, result);
int code = 0;
try {
code = session.getExitStatus();
log.info("执行命令execute1[{}],操作码为[{}],返回结果为[{}]", cmd, code, result);
} catch (Exception e) {
log.error("执行命令出错", e.fillInStackTrace());
} finally {
if (session != null) session.close();
}
return code == 0;
}
/**
* 创建目录
* @param dir
* @return
*/
public String mkdir(String dir) throws BtpDeploySSHExecException {
String cmd = String.format("mkdir -p %s", dir);
try {
return execute(cmd);
} catch (Exception e) {
log.error("创建目录失败,", e);
throw new BtpDeploySSHExecException(e.getMessage());
}
}
public boolean mkdir1(String dir) throws BtpDeploySSHExecException {
String cmd = String.format("mkdir -p %s", dir);
return executeCmd(cmd);
}
public boolean createDirectory(String directory) throws BtpDeploySSHExecException{
return mkdir1(directory);
}
/**
* 解压zip文件到指定目录
* @param zipSrc
* @param distDir
* @return
*/
public boolean unzip(String zipSrc, String distDir) throws BtpDeploySSHExecException {
String cmd = String.format("unzip -oq %s -d %s", zipSrc, distDir);
return executeCmd(cmd);
}
/**
* 修改文件内容
* @param src
* @param dist
* @param filePath
* @return
* @throws Exception
*/
public String replaceInFile(String src, String dist, String filePath) throws BtpDeploySSHExecException {
String cmd = String.format("sed -i 's/%s/%s/' %s", src, dist, filePath);
try {
return execute(cmd);
} catch (Exception e) {
log.error("修改文件内容失败", e);
throw new BtpDeploySSHExecException();
}
}
public boolean rmdir(String filePath) throws BtpDeploySSHExecException {
if (filePath == null || filePath.length() == 0) return false;
for (String path : SAFE_DELETE_FILESYSTEM_PATH_DEFAULT) {
if (path.equalsIgnoreCase(filePath)) throw new BtpDeploySSHExecException(String.format("目录[%s]不允许删除", filePath));
}
String cmd = String.format("rm -rf %s", filePath);
return executeCmd(cmd);
}
protected boolean deleteDirectory(String directory) throws BtpDeploySSHExecException {
if (directory == null || directory.length() == 0 || "/".equalsIgnoreCase(directory)) return true;
String cmd = String.format("rm -rf %s", directory);
return executeCmd(cmd);
}
/**
* 删除文件
* @return
* @throws IOException
*/
protected boolean deleteFile(String filePath) throws BtpDeploySSHExecException {
if (filePath == null || filePath.length() == 0 || "/".equalsIgnoreCase(filePath)) return true;
String cmd = String.format("rm -rf %s", filePath);
return executeCmd(cmd);
}
protected boolean deleteFile1(String filePath) {
try {
return deleteFile(filePath);
} catch (BtpDeploySSHExecException e) {
return false;
}
}
/**
* 文件拷贝:war包+策略zip文件
* src=路径+文件名;des=目的路径
*
* */
public void copyDoucment(String src, String des)
throws BtpDeploySSHExecException {
if (connection == null) throw new BtpDeploySSHExecException("未与服务器建立连接, 不能执行上传文件命令.");
try {
SCPClient scpClient = connection.createSCPClient();
scpClient.put(src, des);
} catch (IOException e) {
log.error("上传文件到远程服务器失败,", e);
throw new BtpDeploySSHExecException();
}
}
/**
* 进入指定目录并返回目录名称
* @param basePath
* @return
* @throws IOException
*/
public String cmdPwd(String basePath) throws BtpDeploySSHExecException {
String cmd = String.format("cd %s && pwd", basePath);
try {
return execute(cmd);
} catch (Exception e) {
log.error(String.format("切换文件目录失败,目录[%s]不存在", basePath), e);
throw new BtpDeploySSHExecException();
}
}
public String moveFile(String oldPath, String newPath) throws BtpDeploySSHExecException {
String cmd = String.format("mv %s %s", oldPath, newPath);
try {
return execute(cmd);
} catch (Exception e) {
log.error(String.format("移动文件失败,原文件[%s]目标目录[%s]不存在", oldPath, newPath), e);
throw new BtpDeploySSHExecException();
}
}
public String lsCmd(String filePath) throws BtpDeploySSHExecException {
String cmd = String.format("ls %s", filePath);
try {
return execute(cmd);
} catch (Exception e) {
log.error(String.format("获取文件路径失败,文件[%s]不存在", filePath), e);
throw new BtpDeploySSHExecException();
}
}
public boolean checkFileExist(String filePath) throws BtpDeploySSHExecException {
String checkFilePath = lsCmd(filePath);
if (filePath.equalsIgnoreCase(checkFilePath)) {
return true;
}
return false;
}
/**
* 上传文件到远程服务器
* @param localFileName
* @param remotePath
* @param remoteFileName
* @throws IOException
*/
public void uploadFileToRemote(String localFileName, String remotePath, String remoteFileName)
throws BtpDeploySSHExecException {
if (connection == null) throw new BtpDeploySSHExecException("未与服务器建立连接, 不能执行上传文件命令.");
try {
SCPClient scpClient = connection.createSCPClient();// 建立SCP客户端:就是为了安全远程传输文件
scpClient.put(localFileName, remoteFileName, remotePath, "0600");
} catch (IOException e) {
log.error("上传文件到远程服务器失败,", e);
throw new BtpDeploySSHExecException();
}
}
public boolean uploadFile2Remote(String localFileName, String remotePath, String remoteFileName) {
try {
uploadFileToRemote(localFileName, remotePath, remoteFileName);
return true;
} catch (Exception e) {
return false;
}
}
protected boolean checkDeployBasePathExist() throws BtpDeploySSHExecException {
String tempPathPwd = cmdPwd(deployBasePath);
if (StringUtils.isBlank(tempPathPwd)) {
log.info("远程服务器上部署根目录在远程服务器上不存在, {}", deployBasePath);
return false;
}
deployBasePath = tempPathPwd;
return true;
}
protected boolean checkDeployPathExist() throws BtpDeploySSHExecException {
String tempPathPwd = cmdPwd(deployPath);
if (StringUtils.isBlank(tempPathPwd)) {
log.info("远程服务器上部署目录在远程服务器上不存在{}", deployPath);
return false;
}
deployPath = tempPathPwd;
return true;
}
protected boolean dos2unix(String filePath) throws BtpDeploySSHExecException {
if (filePath == null || filePath.length() == 0) return false;
String cmd = String.format("dos2unix %s", filePath);
return executeCmd(cmd);
}
protected String getFileName(String filename) {
if (filename == null || filename.length() == 0) return null;
return filename.substring(0, filename.lastIndexOf("."));
}
private void preHandleSession(Session session) throws IOException {
session.requestPTY("vt100");
}
private static List<String> SAFE_DELETE_FILESYSTEM_PATH_DEFAULT
= new ArrayList<String>(16);
static {
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/");
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/boot");
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/home");
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/opt");
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/usr");
SAFE_DELETE_FILESYSTEM_PATH_DEFAULT.add("/etc");
}
}
具体操作类通过实现
BtpAbastractSSHApamaService类即可