|
|
@@ -0,0 +1,270 @@
|
|
|
+package cn.reghao.bnt.web.devops.deployer.util;
|
|
|
+
|
|
|
+import cn.reghao.bnt.web.devops.deployer.model.po.RemoteHost;
|
|
|
+import cn.reghao.bnt.web.devops.deployer.model.UserInfoImpl;
|
|
|
+import cn.reghao.jutil.jdk.io.TextFile;
|
|
|
+import cn.reghao.jutil.jdk.shell.ShellResult;
|
|
|
+import com.jcraft.jsch.*;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Objects;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author reghao
|
|
|
+ * @date 2024-02-19 11:38:54
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+public class Sftp {
|
|
|
+ private final TextFile textFile = new TextFile();
|
|
|
+ private final String bash = "/usr/bin/bash";
|
|
|
+
|
|
|
+ public Session getSession(RemoteHost remoteHost) throws Exception {
|
|
|
+ String host = remoteHost.getHost();
|
|
|
+ int port = remoteHost.getPort();
|
|
|
+ String username = remoteHost.getUsername();
|
|
|
+ String password = remoteHost.getPassword();
|
|
|
+ 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 (remoteHost.getAuthType().equals("password")) {
|
|
|
+ //设置登陆主机的密码
|
|
|
+ session.setPassword(password);
|
|
|
+ //设置第一次登陆的时候提示,可选值:(ask | yes | no)
|
|
|
+ session.setConfig("StrictHostKeyChecking", "no");
|
|
|
+ } else if (remoteHost.getAuthType().equals("privateKey")) {
|
|
|
+ String privateKey = remoteHost.getPrivateKey();
|
|
|
+ String prikeyPath = "";
|
|
|
+
|
|
|
+ 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);
|
|
|
+ InputStream input = channel.getInputStream();
|
|
|
+ InputStream error = channel.getErrStream();
|
|
|
+
|
|
|
+ // timeout 设置为 10 分钟
|
|
|
+ channel.connect(600_000);
|
|
|
+ /*byte[] tmp = new byte[1024];
|
|
|
+ int i = 0;
|
|
|
+ while (true) {
|
|
|
+ while (input.available() > 0) {
|
|
|
+ i = input.read(tmp, 0, 1024);
|
|
|
+ if (i < 0) {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (channel.isClosed()) {
|
|
|
+ if (input.available() > 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("channel closed with status: {}", channel.getExitStatus());
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ Thread.sleep(1000);
|
|
|
+ } catch(Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ sb.append(new String(tmp, 0, i));
|
|
|
+ */
|
|
|
+ // stdin
|
|
|
+ BufferedReader inputReader = new BufferedReader(new InputStreamReader(input));
|
|
|
+ String line;
|
|
|
+ while((line = inputReader.readLine()) != null) {
|
|
|
+ sb.append(line).append(System.lineSeparator());
|
|
|
+ }
|
|
|
+
|
|
|
+ // stderr
|
|
|
+ StringBuilder sb1 = new StringBuilder();
|
|
|
+ BufferedReader errorReader = new BufferedReader(new InputStreamReader(error));
|
|
|
+ String line1;
|
|
|
+ while((line1 = errorReader.readLine()) != null) {
|
|
|
+ sb1.append(line1).append(System.lineSeparator());
|
|
|
+ }
|
|
|
+
|
|
|
+ int statusCode = channel.getExitStatus();
|
|
|
+ ShellResult shellResult = new ShellResult(statusCode);
|
|
|
+ if (statusCode == 0) {
|
|
|
+ shellResult.setResult(sb.toString());
|
|
|
+ } else {
|
|
|
+ shellResult.setResult(sb1.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+ if (channel.isConnected()) {
|
|
|
+ channel.disconnect();
|
|
|
+ }
|
|
|
+
|
|
|
+ return shellResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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 && %s shutdown.sh", remoteDir, bash);
|
|
|
+ ShellResult shellResult = exec(session, command);
|
|
|
+ if (!shellResult.isSuccess()) {
|
|
|
+ log.info("shutdown application failed\nexitCode: {}\nresult:\n{}", shellResult.getExitCode(), shellResult.getResult());
|
|
|
+ System.exit(-1);
|
|
|
+ } 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 && %s start.sh", remoteDir, bash);
|
|
|
+ ShellResult shellResult = exec(session, command);
|
|
|
+ if (!shellResult.isSuccess()) {
|
|
|
+ log.info("start application failed\nexitCode: {}\nresult:\n{}", shellResult.getExitCode(), shellResult.getResult());
|
|
|
+ System.exit(-1);
|
|
|
+ } else {
|
|
|
+ log.info("start application successfully");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (session.isConnected()) {
|
|
|
+ session.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void exec(RemoteHost remoteHost, String command) throws Exception {
|
|
|
+ Session session = getSession(remoteHost);
|
|
|
+ ShellResult shellResult = exec(session, command);
|
|
|
+ log.info("\nexitCode: {}\nresult:\n{}", shellResult.getExitCode(), shellResult.getResult());
|
|
|
+
|
|
|
+ if (session.isConnected()) {
|
|
|
+ session.disconnect();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public static void main(String[] args) throws Exception {
|
|
|
+ String host = "192.168.0.180";
|
|
|
+ int port = 22;
|
|
|
+ String username = "root";
|
|
|
+ String password = "gsh";
|
|
|
+ RemoteHost remoteHost = new RemoteHost(host, port, username, password);
|
|
|
+
|
|
|
+ String command = "docker ps -a";
|
|
|
+ Sftp sftp = new Sftp();
|
|
|
+ sftp.exec(remoteHost, command);
|
|
|
+ }
|
|
|
+}
|