From cbee3797feba63fb4288bc29ba7fdad493fbf316 Mon Sep 17 00:00:00 2001 From: opensnail <598092184@qq.com> Date: Sat, 14 Dec 2024 12:51:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:(unify):=20=E5=AE=8C=E6=88=90=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E7=9A=84=E6=8B=89=E5=8E=BB=E5=92=8C=E7=BC=96=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- snail-job-server/pom.xml | 12 ++ snail-job-server/snail-job-server-web/pom.xml | 9 ++ .../web/controller/DockerController.java | 44 ++++++ .../web/controller/FileViewerController.java | 52 +++++-- .../web/controller/PythonController.java | 17 +++ .../base/SjBuildImageResultCallback.java | 72 ++++++++++ .../server/web/model/enums/FileTypeEnum.java | 14 ++ .../web/model/request/RunPythonRequestVO.java | 11 ++ .../web/model/response/ContainerVO.java | 31 +++++ .../server/web/model/response/FileVO.java | 14 ++ .../web/model/response/SaveFileRequestVO.java | 2 - .../server/web/service/DockerService.java | 21 +++ .../server/web/service/PythonService.java | 9 ++ .../web/service/handler/DockerHandler.java | 37 +++++ .../web/service/impl/DockerServiceImpl.java | 131 ++++++++++++++++++ .../web/service/impl/PythonServiceImpl.java | 77 ++++++++++ 16 files changed, 537 insertions(+), 16 deletions(-) create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/DockerController.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/PythonController.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/base/SjBuildImageResultCallback.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/enums/FileTypeEnum.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/RunPythonRequestVO.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/ContainerVO.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/FileVO.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/DockerService.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/PythonService.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/DockerHandler.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/DockerServiceImpl.java create mode 100644 snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/PythonServiceImpl.java diff --git a/snail-job-server/pom.xml b/snail-job-server/pom.xml index ce286592a..f5bf892f3 100644 --- a/snail-job-server/pom.xml +++ b/snail-job-server/pom.xml @@ -31,6 +31,7 @@ 4.4.0 0.9.16 33.2.0-jre + 3.4.0 @@ -120,6 +121,17 @@ perf4j ${perf4j.version} + + com.github.docker-java + docker-java + ${docker-java.version} + + + + com.github.docker-java + docker-java-transport-okhttp + ${docker-java.version} + diff --git a/snail-job-server/snail-job-server-web/pom.xml b/snail-job-server/snail-job-server-web/pom.xml index 746d45758..ac3011434 100644 --- a/snail-job-server/snail-job-server-web/pom.xml +++ b/snail-job-server/snail-job-server-web/pom.xml @@ -95,6 +95,15 @@ cn.hutool hutool-crypto + + com.github.docker-java + docker-java + + + + com.github.docker-java + docker-java-transport-okhttp + diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/DockerController.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/DockerController.java new file mode 100644 index 000000000..15b86114f --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/DockerController.java @@ -0,0 +1,44 @@ +package com.aizuda.snailjob.server.web.controller; + +import com.aizuda.snailjob.server.web.model.response.ContainerVO; +import com.aizuda.snailjob.server.web.service.DockerService; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Frame; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/docker") +@RequiredArgsConstructor +public class DockerController { + + private final DockerService dockerService; + + @GetMapping("/container/list") + public List getContainerList(@RequestParam("containerName") String containerName) { + return dockerService.getContainerList(containerName); + } + + @GetMapping("/container/{id}") + public InspectContainerResponse getContainerById(@PathVariable("id") String id) { + return dockerService.getContainerById(id); + } + + @GetMapping("/container/log/{id}") + public ResultCallback getContainerLogById(@PathVariable("id") String id) throws InterruptedException { + return dockerService.getContainerLogById(id); + } + + @GetMapping("/create/container") + public boolean createContainer(@RequestParam("containerName") String containerName, @RequestParam("imageName") String imageName) { + return dockerService.createContainer(containerName, imageName); + } + + @GetMapping("/build/image") + public boolean buildImage(@RequestParam("imagerName") String imagerName, @RequestParam("path") String path) { + return dockerService.buildImage(imagerName, path); + } +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/FileViewerController.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/FileViewerController.java index 6cab264ad..1d9c1a8b5 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/FileViewerController.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/FileViewerController.java @@ -1,41 +1,70 @@ package com.aizuda.snailjob.server.web.controller; +import cn.hutool.core.io.FileUtil; +import cn.hutool.core.util.StrUtil; import com.aizuda.snailjob.server.common.exception.SnailJobServerException; +import com.aizuda.snailjob.server.web.model.enums.FileTypeEnum; +import com.aizuda.snailjob.server.web.model.response.FileVO; import com.aizuda.snailjob.server.web.model.response.SaveFileRequestVO; import com.aizuda.snailjob.server.web.model.response.ViewFileResponseVO; import com.google.common.collect.Lists; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.util.Comparator; import java.util.List; +import java.util.stream.Collectors; @RestController @RequestMapping("/file") @RequiredArgsConstructor public class FileViewerController { + // todo 用户配置或者默认是运行jar的所在目录 + private static final String workdir = "/Users/zhangshuguang/"; // 显示文件列表 @GetMapping("/files") - public List listFiles(@RequestParam("rootPath") String rootPath) { + public List listFiles(@RequestParam(value = "directory") String directory) { try { // 读取目录下的文件列表 - return Files.list(Paths.get(rootPath)) - .map(path -> path.getFileName().toString()) - .toList(); + return Files.list(Paths.get(workdir + StrUtil.SLASH + directory)) + .map(path ->{ + File file = path.toFile(); + FileVO fileVO = new FileVO(); + fileVO.setFileName(file.getName()); +// fileVO.setFilePath(file.getPath()); + if (file.isDirectory()) { + fileVO.setFileType(FileTypeEnum.DIRECTORY.getType()); + } else { + fileVO.setFileType(FileTypeEnum.FILE.getType()); + } + return fileVO; + }) + .toList().stream().sorted(new Comparator() { + @Override + public int compare(FileVO o1, FileVO o2) { + if (o2.getFileType().compareTo(o1.getFileType()) == 0) { + return o1.getFileName().compareTo(o2.getFileName()); + } + return o2.getFileType().compareTo(o1.getFileType()); + } + }).collect(Collectors.toList()); } catch (IOException e) { throw new SnailJobServerException("获取文件列表失败", e); } } // 显示文件内容 - @GetMapping("/file") - public ViewFileResponseVO viewFile(@RequestParam("fileName") String fileName, @RequestParam("fullPath") String fullPath) { + @GetMapping("/detail") + public ViewFileResponseVO viewFile(@RequestParam(value = "directory") String directory) { try { // 构建文件路径 - String filePath = Paths.get(fullPath, fileName).toString(); + String filePath = Paths.get(workdir + StrUtil.SLASH + directory).toString(); // 读取文件内容 String s = Files.readString(Paths.get(filePath)); @@ -48,14 +77,9 @@ public class FileViewerController { } // 保存修改后的文件内容 - @PostMapping("/file") + @PutMapping public Boolean saveFile(@RequestBody SaveFileRequestVO requestVO) { - try { - String filePath = Paths.get(requestVO.getFilePath(), requestVO.getFileName()).toString(); - Files.writeString(Paths.get(filePath), requestVO.getContent()); // 更新文件内容 + FileUtil.writeUtf8String(requestVO.getContent().trim(), workdir + StrUtil.SLASH + requestVO.getFileName()); return true; - } catch (IOException e) { - throw new SnailJobServerException("文件更新时候", e); - } } } diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/PythonController.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/PythonController.java new file mode 100644 index 000000000..885fcd4ad --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/controller/PythonController.java @@ -0,0 +1,17 @@ +package com.aizuda.snailjob.server.web.controller; + +import com.aizuda.snailjob.server.web.model.request.RunPythonRequestVO; +import com.aizuda.snailjob.server.web.service.PythonService; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/python") +@RequiredArgsConstructor +public class PythonController { + private final PythonService pythonService; + @PostMapping("/run") + public Boolean run(@RequestBody RunPythonRequestVO requestVO) { + return pythonService.runPython(requestVO); + } +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/base/SjBuildImageResultCallback.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/base/SjBuildImageResultCallback.java new file mode 100644 index 000000000..74028bd09 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/base/SjBuildImageResultCallback.java @@ -0,0 +1,72 @@ +package com.aizuda.snailjob.server.web.model.base; + +import com.github.dockerjava.api.async.ResultCallbackTemplate; +import com.github.dockerjava.api.exception.DockerClientException; +import com.github.dockerjava.api.model.BuildResponseItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.concurrent.TimeUnit; + +public class SjBuildImageResultCallback extends ResultCallbackTemplate { + + private static final Logger LOGGER = LoggerFactory.getLogger(com.github.dockerjava.api.command.BuildImageResultCallback.class); + + private String imageId; + + private String error; + + @Override + public void onNext(BuildResponseItem item) { + if (item.isBuildSuccessIndicated()) { + this.imageId = item.getImageId(); + } else if (item.isErrorIndicated()) { + this.error = item.getError(); + } + LOGGER.info("{}", item.getStream()); + } + + /** + * Awaits the image id from the response stream. + * + * @throws DockerClientException + * if the build fails. + */ + public String awaitImageId() { + try { + awaitCompletion(); + } catch (InterruptedException e) { + throw new DockerClientException("", e); + } + + return getImageId(); + } + + /** + * Awaits the image id from the response stream. + * + * @throws DockerClientException + * if the build fails or the timeout occurs. + */ + public String awaitImageId(long timeout, TimeUnit timeUnit) { + try { + awaitCompletion(timeout, timeUnit); + } catch (InterruptedException e) { + throw new DockerClientException("Awaiting image id interrupted: ", e); + } + + return getImageId(); + } + + private String getImageId() { + if (error != null) { + throw new DockerClientException("Could not build image: " + error); + } + + if (imageId != null) { + return imageId; + } + + throw new DockerClientException("Could not build image"); + } +} \ No newline at end of file diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/enums/FileTypeEnum.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/enums/FileTypeEnum.java new file mode 100644 index 000000000..eba738ace --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/enums/FileTypeEnum.java @@ -0,0 +1,14 @@ +package com.aizuda.snailjob.server.web.model.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum FileTypeEnum { + + FILE(1), + DIRECTORY(2); + + private final int type; +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/RunPythonRequestVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/RunPythonRequestVO.java new file mode 100644 index 000000000..132ac94b6 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/request/RunPythonRequestVO.java @@ -0,0 +1,11 @@ +package com.aizuda.snailjob.server.web.model.request; + +import lombok.Data; + +@Data +public class RunPythonRequestVO { + + private String pythonPath; + + private String command; +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/ContainerVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/ContainerVO.java new file mode 100644 index 000000000..4068fb92a --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/ContainerVO.java @@ -0,0 +1,31 @@ +package com.aizuda.snailjob.server.web.model.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@Data +public class ContainerVO { + + private String id; + + private String name; + + private String image; + + private String status; + + private String state; + + private List ports; + + @Data + public static class ContainerPortVO { + private String ip; + private Integer privatePort; + private Integer publicPort; + private String type; + } + +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/FileVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/FileVO.java new file mode 100644 index 000000000..dfffb55e9 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/FileVO.java @@ -0,0 +1,14 @@ +package com.aizuda.snailjob.server.web.model.response; + +import com.aizuda.snailjob.server.web.model.enums.FileTypeEnum; +import lombok.Data; + +@Data +public class FileVO { + + private String fileName; + + private String filePath; + + private Integer fileType; +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/SaveFileRequestVO.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/SaveFileRequestVO.java index 5cc19234c..d439062d9 100644 --- a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/SaveFileRequestVO.java +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/model/response/SaveFileRequestVO.java @@ -1,10 +1,8 @@ package com.aizuda.snailjob.server.web.model.response; -import lombok.Builder; import lombok.Data; @Data -@Builder public class SaveFileRequestVO { private String fileName; diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/DockerService.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/DockerService.java new file mode 100644 index 000000000..c21434f85 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/DockerService.java @@ -0,0 +1,21 @@ +package com.aizuda.snailjob.server.web.service; + +import com.aizuda.snailjob.server.web.model.response.ContainerVO; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.command.InspectContainerResponse; +import com.github.dockerjava.api.model.Frame; + +import java.util.List; + +public interface DockerService { + + boolean buildImage(String groupName, String path); + + boolean createContainer(String containerName, String imageName); + + List getContainerList(String containerName); + + InspectContainerResponse getContainerById(String id); + + ResultCallback getContainerLogById(String id) throws InterruptedException; +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/PythonService.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/PythonService.java new file mode 100644 index 000000000..86795ccaa --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/PythonService.java @@ -0,0 +1,9 @@ +package com.aizuda.snailjob.server.web.service; + +import com.aizuda.snailjob.server.web.model.request.RunPythonRequestVO; + +public interface PythonService { + + boolean runPython(RunPythonRequestVO pythonPath); + +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/DockerHandler.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/DockerHandler.java new file mode 100644 index 000000000..5376aab90 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/handler/DockerHandler.java @@ -0,0 +1,37 @@ +package com.aizuda.snailjob.server.web.service.handler; + +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.core.DefaultDockerClientConfig; +import com.github.dockerjava.core.DockerClientBuilder; +import com.github.dockerjava.okhttp.OkDockerHttpClient; +import org.springframework.stereotype.Component; + +@Component +public class DockerHandler { + + public DockerClient getDockerClient() { + + DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() + .withDockerTlsVerify(false) + // 这里填最上面填的ip端口号,ip换成服务器ip + .withDockerHost("unix:///var/run/docker.sock") + // docker API版本号,可以用docker version查看 +// .withApiVersion("1.41") + // 默认 +// .withRegistryUrl("https://index.docker.io/v1/") + .build(); + + OkDockerHttpClient build = new OkDockerHttpClient.Builder() + .dockerHost(config.getDockerHost()) + .sslConfig(config.getSSLConfig()) + .connectTimeout(30 * 100) + .build(); + + // Create Docker client + return DockerClientBuilder + .getInstance(config) + .withDockerHttpClient(build) + .build(); + + } +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/DockerServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/DockerServiceImpl.java new file mode 100644 index 000000000..3a31a77a2 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/DockerServiceImpl.java @@ -0,0 +1,131 @@ +package com.aizuda.snailjob.server.web.service.impl; + +import com.aizuda.snailjob.common.core.util.StreamUtils; +import com.aizuda.snailjob.server.common.util.DateUtils; +import com.aizuda.snailjob.server.web.model.base.SjBuildImageResultCallback; +import com.aizuda.snailjob.server.web.model.response.ContainerVO; +import com.aizuda.snailjob.server.web.service.DockerService; +import com.aizuda.snailjob.server.web.service.handler.DockerHandler; +import com.github.dockerjava.api.DockerClient; +import com.github.dockerjava.api.async.ResultCallback; +import com.github.dockerjava.api.async.ResultCallbackTemplate; +import com.github.dockerjava.api.command.*; +import com.github.dockerjava.api.model.Container; +import com.github.dockerjava.api.model.ContainerPort; +import com.github.dockerjava.api.model.Frame; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + +import static com.aizuda.snailjob.server.common.util.DateUtils.PURE_DATETIME_MS_PATTERN; + +@Service +@RequiredArgsConstructor +public class DockerServiceImpl implements DockerService { + private final DockerHandler dockerHandler; + + @Override + public boolean buildImage(String groupName, String path) { + String format = String.format("sj_%s_%s", groupName, DateUtils.toNowFormat(PURE_DATETIME_MS_PATTERN)); + DockerClient dockerClient = dockerHandler.getDockerClient(); + BuildImageCmd imageCmd = dockerClient + .buildImageCmd(new File(path)) + .withTags(Sets.newHashSet(format)); + imageCmd.exec(new SjBuildImageResultCallback()).awaitImageId(); + + return false; + } + + @Override + public boolean createContainer(String containerName, String imageName) { + DockerClient dockerClient = dockerHandler.getDockerClient(); + String image = String.format("%s:latest", imageName); + containerName = String.format("sj_%s_%s", containerName, DateUtils.toNowFormat(PURE_DATETIME_MS_PATTERN)); + + // Pull an image +// try { +// dockerClient.pullImageCmd(String.format("%s:latest", imageName)).start().awaitCompletion(); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } + Map labels = Maps.newHashMap(); + labels.put("name", "snail_job"); + + // Create a container + CreateContainerResponse container = dockerClient + .createContainerCmd(image) + .withName(containerName) + .withLabels(labels) +// .withCmd("echo", "Hello, Docker-Java!") + .exec(); + + // Start the container + dockerClient.startContainerCmd(container.getId()).exec(); + + return false; + } + + @Override + public List getContainerList(String containerName) { + DockerClient dockerClient = dockerHandler.getDockerClient(); + Map labels = Maps.newHashMap(); + labels.put("app-name", "snail-job-server"); + ListContainersCmd listContainersCmd = dockerClient.listContainersCmd(); + + List containerList = listContainersCmd.withLabelFilter(labels).withShowAll(true).exec(); + + return StreamUtils.toList(containerList, container -> { + ContainerVO containerVO = new ContainerVO(); + containerVO.setId(container.getId()); + containerVO.setImage(container.getImage()); + containerVO.setName(container.getNames()[0]); + containerVO.setStatus(container.getStatus()); + containerVO.setState(container.getState()); + List portVOS = StreamUtils.toList(Arrays.stream(container.getPorts()).toList(), new Function() { + + @Override + public ContainerVO.ContainerPortVO apply(ContainerPort containerPort) { + ContainerVO.ContainerPortVO portVO = new ContainerVO.ContainerPortVO(); + portVO.setPublicPort(containerPort.getPublicPort()); + portVO.setPrivatePort(containerPort.getPrivatePort()); + portVO.setIp(containerPort.getIp()); + portVO.setType(containerPort.getType()); + return portVO; + } + }); + + containerVO.setPorts(portVOS); + return containerVO; + }); + } + + @Override + public InspectContainerResponse getContainerById(String id) { + DockerClient dockerClient = dockerHandler.getDockerClient(); + return dockerClient.inspectContainerCmd(id).exec(); + } + + @Override + public ResultCallback getContainerLogById(String id) throws InterruptedException { + DockerClient dockerClient = dockerHandler.getDockerClient(); + return dockerClient.logContainerCmd(id) + .withStdErr(true) + .withStdOut(true) + .withFollowStream(true) + .withTailAll() + .exec(new ResultCallbackTemplate<>() { + @Override + public void onNext(Frame object) { + // ws处理 + System.out.println(object); + } + }).awaitStarted(); + } +} diff --git a/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/PythonServiceImpl.java b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/PythonServiceImpl.java new file mode 100644 index 000000000..f27a71a68 --- /dev/null +++ b/snail-job-server/snail-job-server-web/src/main/java/com/aizuda/snailjob/server/web/service/impl/PythonServiceImpl.java @@ -0,0 +1,77 @@ +package com.aizuda.snailjob.server.web.service.impl; + +import cn.hutool.core.util.StrUtil; +import com.aizuda.snailjob.server.web.model.request.RunPythonRequestVO; +import com.aizuda.snailjob.server.web.service.PythonService; +import org.springframework.stereotype.Service; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; + +@Service +public class PythonServiceImpl implements PythonService { + + private static final String workdir = "/Users/zhangshuguang/"; + + @Override + public boolean runPython(RunPythonRequestVO requestVO) { + return execPython(requestVO); + } + + public boolean execPython(RunPythonRequestVO requestVO) { + try { + + String command = requestVO.getCommand(); + + String[] split = command.split("&&"); + // Python 脚本路径 + String pythonScriptPath = workdir + StrUtil.SLASH + requestVO.getPythonPath(); + String pythonScriptTxt = workdir + StrUtil.SLASH + StrUtil.replaceFirst(requestVO.getPythonPath(), "main.py", "requirements.txt"); + + // 构建命令 + ProcessBuilder pipBuilder = new ProcessBuilder(split[0], pythonScriptTxt); + pipBuilder.redirectErrorStream(true); + + // 启动进程 + Process pipProcess = pipBuilder.start(); + + printProcessOutput(pipProcess); + + // 等待脚本执行结束 + int pipExitCode = pipProcess.waitFor(); + if (pipExitCode != 0) { + System.out.println("Script exited with code: " + pipExitCode); + return false; + } + // 构建命令 + ProcessBuilder processBuilder = new ProcessBuilder(split[1], pythonScriptPath); + processBuilder.redirectErrorStream(true); + + // 启动进程 + Process process = processBuilder.start(); + + printProcessOutput(process); + + // 等待脚本执行结束 + int exitCode = process.waitFor(); + if (exitCode != 0) { + System.out.println("Script exited with code: " + exitCode); + } + + } catch (Exception e) { + e.printStackTrace(); + } + + return true; + } + + private static void printProcessOutput(Process process) throws IOException { + // 获取脚本输出 + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + } +}