|
|
@@ -0,0 +1,233 @@
|
|
|
+package cn.reghao.devops.deployer.util;
|
|
|
+
|
|
|
+import cn.reghao.devops.deployer.model.RemoteHost;
|
|
|
+import cn.reghao.devops.deployer.model.UserInfoImpl;
|
|
|
+import cn.reghao.jutil.jdk.shell.ShellResult;
|
|
|
+import cn.reghao.jutil.jdk.text.TextFile;
|
|
|
+import com.jcraft.jsch.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author reghao
|
|
|
+ * @date 2024-02-19 11:38:54
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class Sftp {
|
|
|
+ private final TextFile textFile = new TextFile();
|
|
|
+
|
|
|
+ public Session getSession(RemoteHost remoteHost) throws Exception {
|
|
|
+ String host = remoteHost.getHost();
|
|
|
+ int port = remoteHost.getPort();
|
|
|
+ String username = remoteHost.getUsername();
|
|
|
+ String password = remoteHost.getPassword();
|
|
|
+ String prikeyPath = remoteHost.getPrikeyPath();
|
|
|
+
|
|
|
+ JSch jsch = new JSch();
|
|
|
+ Session session;
|
|
|
+ if (port <= 0) {
|
|
|
+ //连接服务器,采用默认端口
|
|
|
+ session = jsch.getSession(username, host);
|
|
|
+ } else {
|
|
|
+ //采用指定的端口连接服务器
|
|
|
+ session = jsch.getSession(username, host, port);
|
|
|
+ }
|
|
|
+
|
|
|
+ //如果服务器连接不上,则抛出异常
|
|
|
+ if (session == null) {
|
|
|
+ throw new Exception("session is null");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (password != null) {
|
|
|
+ //设置登陆主机的密码
|
|
|
+ session.setPassword(password);
|
|
|
+ //设置第一次登陆的时候提示,可选值:(ask | yes | no)
|
|
|
+ session.setConfig("StrictHostKeyChecking", "no");
|
|
|
+ } else if (prikeyPath != null) {
|
|
|
+ session.setConfig("PreferredAuthentications", "publickey");
|
|
|
+ session.setConfig("userauth.gssapi-with-mic", "no");
|
|
|
+ session.setConfig("StrictHostKeyChecking", "ask");
|
|
|
+ session.setUserInfo(new UserInfoImpl(""));
|
|
|
+ jsch.addIdentity(prikeyPath);
|
|
|
+
|
|
|
+ session.setConfig("UseDNS", "no");
|
|
|
+ session.setConfig("kex", "diffie-hellman-group1-sha1,"
|
|
|
+ + "diffie-hellman-group-exchange-sha1,"
|
|
|
+ + "diffie-hellman-group-exchange-sha256");
|
|
|
+ } else {
|
|
|
+ throw new Exception("password and private key not exist either");
|
|
|
+ }
|
|
|
+
|
|
|
+ session.connect(30_000);
|
|
|
+ return session;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void upload(Session session, String local, String destDir) throws JSchException, SftpException, IOException {
|
|
|
+ // 创建 sftp 通信通道
|
|
|
+ Channel channel = session.openChannel("sftp");
|
|
|
+ channel.connect(5_000);
|
|
|
+ ChannelSftp sftp = (ChannelSftp) channel;
|
|
|
+ sftp.cd(destDir);
|
|
|
+ File localFile = new File(local);
|
|
|
+ if (localFile.isFile()) {
|
|
|
+ putFile(localFile, destDir, sftp);
|
|
|
+ } else {
|
|
|
+ for (File file : Objects.requireNonNull(localFile.listFiles())) {
|
|
|
+ if (file.isFile()) {
|
|
|
+ putFile(file, destDir, sftp);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (channel.isConnected()) {
|
|
|
+ channel.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void putFile(File localFile, String destDir, ChannelSftp sftp) throws IOException, SftpException {
|
|
|
+ String filename = localFile.getName();
|
|
|
+ String remoteFilePath = String.format("%s/%s", destDir, filename);
|
|
|
+ OutputStream outstream = sftp.put(remoteFilePath);
|
|
|
+
|
|
|
+ InputStream instream = new FileInputStream(localFile);
|
|
|
+ byte[] bytes = new byte[1024];
|
|
|
+ int n;
|
|
|
+ while ((n = instream.read(bytes)) != -1) {
|
|
|
+ outstream.write(bytes, 0, n);
|
|
|
+ }
|
|
|
+
|
|
|
+ outstream.flush();
|
|
|
+ outstream.close();
|
|
|
+ instream.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 在远程机器上创建目录(等价于 mkdir -p)
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2024-02-20 09:20:11
|
|
|
+ */
|
|
|
+ public boolean mkdir(Session session, String remotePath) throws SftpException, JSchException {
|
|
|
+ boolean exist = true;
|
|
|
+ // 创建 sftp 通信通道
|
|
|
+ Channel channel = session.openChannel("sftp");
|
|
|
+ channel.connect(5_000);
|
|
|
+ ChannelSftp sftp = (ChannelSftp) channel;
|
|
|
+
|
|
|
+ List<String> list = new ArrayList<>();
|
|
|
+ String[] arr = remotePath.split("/");
|
|
|
+ for (int i = 0; i < arr.length; i++) {
|
|
|
+ String path = "/" + arr[i];
|
|
|
+ if (i-1 > 0) {
|
|
|
+ list.add(list.get(i-1) + path);
|
|
|
+ } else {
|
|
|
+ list.add(path);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ for (String path : list) {
|
|
|
+ try {
|
|
|
+ sftp.stat(path);
|
|
|
+ } catch (SftpException e) {
|
|
|
+ exist = false;
|
|
|
+ sftp.mkdir(path);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return exist;
|
|
|
+ }
|
|
|
+
|
|
|
+ public ShellResult exec(Session session, String command) throws JSchException, IOException {
|
|
|
+ StringBuilder sb = new StringBuilder();
|
|
|
+ // 创建 exec 通信通道
|
|
|
+ ChannelExec channel = (ChannelExec) session.openChannel("exec");
|
|
|
+ channel.setCommand(command);
|
|
|
+ channel.setInputStream(null);
|
|
|
+ channel.setErrStream(System.err);
|
|
|
+ channel.connect(10_000);
|
|
|
+ InputStream input = channel.getInputStream();
|
|
|
+ try {
|
|
|
+ BufferedReader inputReader = new BufferedReader(new InputStreamReader(input));
|
|
|
+ String line;
|
|
|
+ while((line = inputReader.readLine()) != null) {
|
|
|
+ sb.append(line).append(System.lineSeparator());
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ if (input != null) {
|
|
|
+ try {
|
|
|
+ input.close();
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ int statusCode = channel.getExitStatus();
|
|
|
+ ShellResult shellResult = new ShellResult(statusCode);
|
|
|
+ shellResult.setResult(sb.toString());
|
|
|
+
|
|
|
+ if (channel.isConnected()) {
|
|
|
+ channel.disconnect();
|
|
|
+ }
|
|
|
+
|
|
|
+ return shellResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ public List<RemoteHost> getRemoteHost(String filePath) {
|
|
|
+ return textFile.read(filePath).stream().map(line -> {
|
|
|
+ String[] arr = line.split(",");
|
|
|
+ if (arr.length == 4) {
|
|
|
+ String host = arr[0];
|
|
|
+ int port = Integer.parseInt(arr[1]);
|
|
|
+ String username = arr[2];
|
|
|
+ String password = arr[3];
|
|
|
+ return new RemoteHost(host, port, username, password, null);
|
|
|
+ } else if (arr.length == 5) {
|
|
|
+ String host = arr[0];
|
|
|
+ int port = Integer.parseInt(arr[1]);
|
|
|
+ String username = arr[2];
|
|
|
+ String prikeyPath = arr[4];
|
|
|
+ return new RemoteHost(host, port, username, null, prikeyPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ return null;
|
|
|
+ }).filter(Objects::nonNull).collect(Collectors.toList());
|
|
|
+ }
|
|
|
+
|
|
|
+ public void deploy(String localDir, String remoteDir, RemoteHost remoteHost) throws Exception {
|
|
|
+ Session session = getSession(remoteHost);
|
|
|
+ boolean exist = mkdir(session, remoteDir);
|
|
|
+ if (exist) {
|
|
|
+ String command = String.format("cd %s && sh shutdown.sh", remoteDir);
|
|
|
+ ShellResult shellResult = exec(session, command);
|
|
|
+ if (!shellResult.isSuccess()) {
|
|
|
+ log.info("shutdown application failed: {} - {}", shellResult.getExitCode(), shellResult.getResult());
|
|
|
+ } else {
|
|
|
+ log.info("shutdown application successfully");
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ log.info("remote dir {} created", remoteDir);
|
|
|
+ }
|
|
|
+
|
|
|
+ upload(session, localDir, remoteDir);
|
|
|
+ log.info("files uploaded");
|
|
|
+
|
|
|
+ String command = String.format("cd %s && sh start.sh", remoteDir);
|
|
|
+ ShellResult shellResult = exec(session, command);
|
|
|
+ if (!shellResult.isSuccess()) {
|
|
|
+ log.info("start application failed: {} - {}", shellResult.getExitCode(), shellResult.getResult());
|
|
|
+ } else {
|
|
|
+ log.info("start application successfully");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (session.isConnected()) {
|
|
|
+ session.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|