diff --git a/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java b/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java index 99726c7..316b7f9 100644 --- a/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java +++ b/web-api/src/main/java/com/jeesite/modules/utils/DockerUtil.java @@ -5,93 +5,32 @@ import com.jeesite.modules.apps.Module.ContainerInfo; import com.jeesite.modules.apps.Module.DockerResult; import com.jeesite.modules.biz.entity.MySftpAccounts; -import java.io.*; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Hashtable; import java.util.List; -/** - * Docker 容器管理工具 - *

- * 通过 SSH 连接主机,基于 MySftpAccounts 凭证执行 docker 命令。 - * 支持密码认证和私钥认证。 - */ public class DockerUtil { private static final int SSH_TIMEOUT = 30000; - public static DockerResult start(MySftpAccounts accounts, String containerId) { - return exec(accounts, "docker start " + containerId); - } - - public static DockerResult stop(MySftpAccounts accounts, String containerId) { - return exec(accounts, "docker stop " + containerId); - } - - public static DockerResult restart(MySftpAccounts accounts, String containerId) { - return exec(accounts, "docker restart " + containerId); - } - - public static DockerResult getLogs(MySftpAccounts accounts, String containerId, - int tail, boolean timestamps) { - String cmd = "docker logs" + (timestamps ? " -t" : "") - + " --tail " + tail + " " + containerId; - return exec(accounts, cmd); - } - - public static DockerResult list(MySftpAccounts accounts, boolean all) { - return exec(accounts, all ? "docker ps -a" : "docker ps"); - } - - public static DockerResult inspect(MySftpAccounts accounts, String containerId) { - return exec(accounts, "docker inspect " + containerId); - } - - public static List listContainers(MySftpAccounts accounts, boolean all) { - List list = new ArrayList<>(); - String cmd = (all ? "docker ps -a" : "docker ps") - + " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\""; - DockerResult r = exec(accounts, cmd); - if (!r.isSuccess()) { - return new ArrayList<>(); - } - for (String line : r.getOutput().split("\n")) { - if (line.trim().isEmpty()) continue; - String[] p = line.split("\\|"); - if (p.length < 2) continue; - ContainerInfo info = new ContainerInfo(); - info.setContainerId(p[0].trim()); - info.setImage(p[1].trim()); - info.setCommand(p.length > 2 ? p[2].trim() : ""); - info.setCreated(p.length > 3 ? p[3].trim() : ""); - info.setStatus(p.length > 4 ? p[4].trim() : ""); - info.setPorts(p.length > 5 ? p[5].trim() : ""); - info.setNames(p.length > 6 ? p[6].trim() : ""); - info.setAccountId(accounts.getAccountId()); - list.add(info); - } - return list; - } - - public static DockerResult exec(MySftpAccounts accounts, String command) { + private static String runCommand(MySftpAccounts account, String cmd) { JSch jsch = new JSch(); Session session = null; ChannelExec channel = null; + try { - int port = accounts.getHostPort() != null ? accounts.getHostPort() : 22; - session = jsch.getSession(accounts.getUsername(), accounts.getHostIp(), port); + int port = account.getHostPort() == null ? 22 : account.getHostPort(); + session = jsch.getSession(account.getUsername(), account.getHostIp(), port); session.setTimeout(SSH_TIMEOUT); - if ("key".equalsIgnoreCase(accounts.getAuthType()) - && accounts.getPrivateKey() != null && !accounts.getPrivateKey().isEmpty()) { - jsch.addIdentity("temp", - accounts.getPrivateKey().getBytes(StandardCharsets.UTF_8), - null, null); - } else if (accounts.getPassword() != null && !accounts.getPassword().isEmpty()) { - session.setPassword(accounts.getPassword()); + // 认证 + if ("key".equalsIgnoreCase(account.getAuthType()) && account.getPrivateKey() != null) { + jsch.addIdentity("temp", account.getPrivateKey().getBytes(StandardCharsets.UTF_8), null, null); } else { - return DockerResult.fail("SSH 认证信息不完整:缺少密码或私钥"); + session.setPassword(account.getPassword()); } Hashtable config = new Hashtable<>(); @@ -99,46 +38,85 @@ public class DockerUtil { session.setConfig(config); session.connect(SSH_TIMEOUT); + // 执行命令 channel = (ChannelExec) session.openChannel("exec"); - String finalCmd = (accounts.getRootPath() != null && !accounts.getRootPath().isEmpty()) - ? "cd " + accounts.getRootPath() + " && " + command - : command; - channel.setCommand(finalCmd); - channel.setInputStream(null); + String command = account.getRootPath() != null && !account.getRootPath().isEmpty() + ? "cd " + account.getRootPath() + " && " + cmd + : cmd; + channel.setCommand(command); InputStream in = channel.getInputStream(); - ByteArrayOutputStream errOut = new ByteArrayOutputStream(); - channel.setExtOutputStream(errOut); - channel.connect(); - StringBuilder outBuilder = new StringBuilder(); - if (in != null) { - byte[] buf = new byte[4096]; - int n; - while ((n = in.read(buf)) != -1) { - outBuilder.append(new String(buf, 0, n, StandardCharsets.UTF_8)); - } + // 读取输出 + ByteArrayOutputStream out = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int len; + while ((len = in.read(buf)) != -1) { + out.write(buf, 0, len); } - String stdout = outBuilder.toString().trim(); - String stderr = errOut.toString(StandardCharsets.UTF_8).trim(); - int exitCode = channel.getExitStatus(); + return out.toString(StandardCharsets.UTF_8).trim(); - if (exitCode == 0) { - return DockerResult.ok(stdout); - } else { - return DockerResult.fail("命令执行失败,退出码: " + exitCode, - stderr.isEmpty() ? stdout : stderr); - } - - } catch (JSchException e) { - return DockerResult.fail("SSH 连接失败: " + e.getMessage()); - } catch (IOException e) { - return DockerResult.fail("IO 异常: " + e.getMessage()); + } catch (Exception e) { + return null; } finally { - if (channel != null && channel.isConnected()) channel.disconnect(); - if (session != null && session.isConnected()) session.disconnect(); + if (channel != null) channel.disconnect(); + if (session != null) session.disconnect(); } } -} + + public static List listContainers(MySftpAccounts accounts, boolean all) { + List list = new ArrayList<>(); + String cmd = (all ? "docker ps -a" : "docker ps") + + " --format \"{{.ID}}|{{.Image}}|{{.Command}}|{{.CreatedAt}}|{{.Status}}|{{.Ports}}|{{.Names}}\""; + + String output = runCommand(accounts, cmd); + if (output == null || output.isBlank()) return list; + for (String line : output.split("\\R")) { + if (line.isBlank()) continue; + String[] arr = line.split("\\|"); + ContainerInfo info = new ContainerInfo(); + info.setContainerId(arr.length > 0 ? arr[0].trim() : ""); + info.setImage(arr.length > 1 ? arr[1].trim() : ""); + info.setCommand(arr.length > 2 ? arr[2].trim() : ""); + info.setCreated(arr.length > 3 ? arr[3].trim() : ""); + info.setStatus(arr.length > 4 ? arr[4].trim() : ""); + info.setPorts(arr.length > 5 ? arr[5].trim() : ""); + info.setNames(arr.length > 6 ? arr[6].trim() : ""); + info.setAccountId(accounts.getAccountId()); + list.add(info); + } + return list; + } + public static DockerResult start(MySftpAccounts accounts, String containerId) { + String res = runCommand(accounts, "docker start " + containerId); + return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败"); + } + + public static DockerResult stop(MySftpAccounts accounts, String containerId) { + String res = runCommand(accounts, "docker stop " + containerId); + return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败"); + } + + public static DockerResult restart(MySftpAccounts accounts, String containerId) { + String res = runCommand(accounts, "docker restart " + containerId); + return res != null ? DockerResult.ok(res) : DockerResult.fail("执行失败"); + } + + public static DockerResult getLogs(MySftpAccounts accounts, String containerId, int tail, boolean timestamps) { + String cmd = "docker logs " + (timestamps ? "-t " : "") + "--tail " + tail + " " + containerId; + String res = runCommand(accounts, cmd); + return res != null ? DockerResult.ok(res) : DockerResult.fail("获取日志失败"); + } + + public static DockerResult list(MySftpAccounts accounts, boolean all) { + String res = runCommand(accounts, all ? "docker ps -a" : "docker ps"); + return res != null ? DockerResult.ok(res) : DockerResult.fail("获取列表失败"); + } + + public static DockerResult inspect(MySftpAccounts accounts, String containerId) { + String res = runCommand(accounts, "docker inspect " + containerId); + return res != null ? DockerResult.ok(res) : DockerResult.fail("查询详情失败"); + } +} \ No newline at end of file diff --git a/web-api/src/main/resources/config/application.yml b/web-api/src/main/resources/config/application.yml index d5c540c..3edd8e6 100644 --- a/web-api/src/main/resources/config/application.yml +++ b/web-api/src/main/resources/config/application.yml @@ -36,12 +36,12 @@ server: #========= Database settings ==========# #======================================# -jdbc: +jdbc: type: mysql driver: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://192.168.31.182:13306/system?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true - username: dream - password: info_dream + url: jdbc:mysql://127.0.0.1:13306/my_app?useSSL=false&allowPublicKeyRetrieval=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=CONVERT_TO_NULL&serverTimezone=Asia/Shanghai&nullCatalogMeansCurrent=true + username: root + password: root_dream testSql: SELECT 1 encrypt: username: false @@ -156,7 +156,7 @@ web: addPathPatterns: > ${frontPath}/** excludePathPatterns: ~ - core: + core: enabled: true # 在线API文档 diff --git a/web-vue/packages/biz/views/biz/myDocker/index.vue b/web-vue/packages/biz/views/biz/myDocker/index.vue index 367db2d..7ed20bf 100644 --- a/web-vue/packages/biz/views/biz/myDocker/index.vue +++ b/web-vue/packages/biz/views/biz/myDocker/index.vue @@ -1,21 +1,347 @@ + +