From cb22cd43c60bccade3f16e38e67512a391fb7c99 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E8=92=B2=E5=85=88=E7=94=9F?= <821039958@qq.com>
Date: Fri, 25 Jul 2025 18:22:47 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B8=8A=E4=BC=A0=E9=95=9C=E5=83=8F=E5=88=B0?=
=?UTF-8?q?=E7=9B=AE=E6=A0=87=E4=B8=BB=E6=9C=BA=E5=8A=9F=E8=83=BD?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
modules/module-ci-execute/pom.xml | 8 ++
.../docker/api/DockerImageController.java | 12 +++
.../convert/DockerImageConvert.java | 20 -----
.../docker/dataobject/model/DockerImage.java | 5 +-
.../execute/docker/service/IImageService.java | 2 +
.../docker/service/impl/ImageService.java | 89 +++++++++++++++++--
6 files changed, 106 insertions(+), 30 deletions(-)
delete mode 100644 modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/convert/DockerImageConvert.java
diff --git a/modules/module-ci-execute/pom.xml b/modules/module-ci-execute/pom.xml
index 3db1d4ef..0ea55e7a 100644
--- a/modules/module-ci-execute/pom.xml
+++ b/modules/module-ci-execute/pom.xml
@@ -27,6 +27,10 @@
cd.casic.boot
spring-boot-starter-test
+
+ cd.casic.boot
+ module-ci-machine
+
com.github.docker-java
docker-java
@@ -61,6 +65,10 @@
jakarta.ws.rs-api
3.1.0
+
+ com.jcraft
+ jsch
+
diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/api/DockerImageController.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/api/DockerImageController.java
index 6c2e43e3..f2b30a02 100644
--- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/api/DockerImageController.java
+++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/api/DockerImageController.java
@@ -7,6 +7,8 @@ import cd.casic.module.execute.docker.dataobject.model.DockerImage;
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
import cd.casic.module.execute.docker.service.IImageService;
import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
@@ -47,4 +49,14 @@ public class DockerImageController {
return success(imageService.getLocalImagePage(pageVO));
}
+ @GetMapping("/localImagePush")
+ @Operation(summary = "镜像推送,或者部署到目标服务器")
+ @Parameters({
+ @Parameter(name = "imageId", description = "镜像id"),
+ @Parameter(name = "machineId", description = "主机id")
+ })
+ @PreAuthorize("@ss.hasPermission('docker:images:localImagePush')")
+ public CommonResult localImagePush(@RequestParam(value = "imageId") String imageId, @RequestParam("machineId") String machineId) {
+ return success(imageService.localImagePush(imageId,machineId));
+ }
}
diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/convert/DockerImageConvert.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/convert/DockerImageConvert.java
deleted file mode 100644
index ee288638..00000000
--- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/convert/DockerImageConvert.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package cd.casic.module.execute.docker.dataobject.convert;
-
-import cd.casic.module.execute.docker.dataobject.dto.DockerImageDo;
-import cd.casic.module.execute.docker.dataobject.model.DockerImage;
-import org.mapstruct.Mapper;
-import org.mapstruct.factory.Mappers;
-
-/**
- *
- * @author Yuru Pu
- * @version 1.0
- * @since 2025/7/23 17:16
- */
-@Mapper(componentModel = "spring")
-public interface DockerImageConvert {
- DockerImageConvert INSTANCE = Mappers.getMapper(DockerImageConvert.class);
-
- DockerImageDo convert(DockerImage dockerImage);
-
-}
diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/DockerImage.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/DockerImage.java
index 02363a2c..2c5383c4 100644
--- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/DockerImage.java
+++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/dataobject/model/DockerImage.java
@@ -1,8 +1,6 @@
package cd.casic.module.execute.docker.dataobject.model;
-import cd.casic.framework.commons.dataobject.BaseDO;
import lombok.Data;
-import lombok.experimental.Accessors;
/**
* 本地镜像
@@ -12,8 +10,7 @@ import lombok.experimental.Accessors;
* @since 2025/7/23 16:22
*/
@Data
-@Accessors(chain = true)
-public class DockerImage extends BaseDO {
+public class DockerImage {
private String id;
diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IImageService.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IImageService.java
index 3486116a..96eb3a01 100644
--- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IImageService.java
+++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/IImageService.java
@@ -109,4 +109,6 @@ public interface IImageService {
int localImageUpload(DockerImage dockerImage);
PageResult getLocalImagePage(DockerImagePageReqVO pageVO);
+
+ Object localImagePush(String imageId, String machineId);
}
diff --git a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/ImageService.java b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/ImageService.java
index c34d787d..251cbab5 100644
--- a/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/ImageService.java
+++ b/modules/module-ci-execute/src/main/java/cd/casic/module/execute/docker/service/impl/ImageService.java
@@ -1,22 +1,33 @@
package cd.casic.module.execute.docker.service.impl;
+import cd.casic.ci.commons.properties.TargetFileUploadProperties;
import cd.casic.framework.commons.pojo.PageResult;
import cd.casic.framework.mybatis.core.query.LambdaQueryWrapperX;
import cd.casic.module.execute.docker.DockerClientFactory;
import cd.casic.module.execute.docker.dao.DockerImageDao;
-import cd.casic.module.execute.docker.dataobject.convert.DockerImageConvert;
import cd.casic.module.execute.docker.dataobject.dto.DockerImageDo;
import cd.casic.module.execute.docker.dataobject.model.DockerImage;
import cd.casic.module.execute.docker.dataobject.vo.DockerImagePageReqVO;
import cd.casic.module.execute.docker.service.IImageService;
+import cd.casic.module.machine.dal.dataobject.MachineInfoDO;
+import cd.casic.module.machine.dal.dataobject.SecretKeyDO;
+import cd.casic.module.machine.dal.mysql.MachineInfoMapper;
+import cd.casic.module.machine.dal.mysql.SecretKeyMapper;
+import cd.casic.module.machine.enums.AuthenticationType;
+import cd.casic.module.machine.utils.CryptogramUtil;
+import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
+import cn.hutool.extra.ftp.FtpConfig;
+import cn.hutool.extra.ssh.JschUtil;
+import cn.hutool.extra.ssh.Sftp;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.InspectImageResponse;
import com.github.dockerjava.api.command.SaveImageCmd;
import com.github.dockerjava.api.exception.NotFoundException;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.PruneType;
+import com.jcraft.jsch.Session;
import jakarta.annotation.Nonnull;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
@@ -24,11 +35,11 @@ import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
import java.util.List;
+import java.util.Objects;
+import java.util.UUID;
/**
* @description: 镜像的服务类
@@ -46,6 +57,15 @@ public class ImageService implements IImageService {
@Resource
private DockerImageDao dockerImageDao;
+ @Resource
+ private MachineInfoMapper machineInfoMapper;
+
+ @Resource
+ private TargetFileUploadProperties fileUploadProperties;
+
+ @Resource
+ private SecretKeyMapper secretKeyMapper;
+
@Override
public List list(@Nonnull String clientId) {
DockerClient dockerClient = dockerClientFactory.getdockerClient(clientId);
@@ -144,7 +164,9 @@ public class ImageService implements IImageService {
@Transactional(rollbackFor = Exception.class)
@Override
public int localImageUpload(DockerImage dockerImage) {
- return dockerImageDao.insert(DockerImageConvert.INSTANCE.convert(dockerImage));
+ DockerImageDo imageDo = new DockerImageDo();
+ BeanUtil.copyProperties(dockerImage,imageDo);
+ return dockerImageDao.insert(imageDo);
}
@Override
@@ -153,4 +175,59 @@ public class ImageService implements IImageService {
PageResult page = dockerImageDao.selectPage(pageVO, queryWrapperX.likeIfPresent(DockerImageDo::getName, pageVO.getName()).orderByDesc(DockerImageDo::getCreateTime));
return page;
}
+
+ /**
+ * 先下载后上传到目标主机
+ * @param imageId
+ * @param machineId
+ * @return
+ */
+ @Override
+ public Object localImagePush(String imageId, String machineId) {
+ if (Objects.isNull(imageId) || Objects.isNull(machineId)) {
+ return null;
+ }
+ DockerImageDo imageDo = dockerImageDao.selectById(imageId);
+ //1 远程下载
+ // 1.1 建立连接 下载
+ Sftp sftp = getSftp(FtpConfig.create().setHost(fileUploadProperties.getRemoteHost()).setPort(fileUploadProperties.getRemotePort()).setUser(fileUploadProperties.getUsername()).setPassword(fileUploadProperties.getPassword()));
+ String srcPath = imageDo.getPath();
+ ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
+ sftp.download(srcPath, byteOut); //远程下载到中间缓存区
+ sftp.close();
+ // 2 建立连接 区分密码还是秘钥
+ MachineInfoDO machineInfoDO = machineInfoMapper.selectById(machineId);
+ FtpConfig targetFtp = FtpConfig.create().setHost(machineInfoDO.getHostIp()).setPort(machineInfoDO.getSshPort()).setUser(machineInfoDO.getUsername()).setPassword(CryptogramUtil.doDecrypt(machineInfoDO.getPassword()));
+ if (AuthenticationType.of(machineInfoDO.getAuthenticationType()).equals(AuthenticationType.SECRET_KEY)) {
+ SecretKeyDO secretKeyDO = secretKeyMapper.selectById(machineInfoDO.getSecretKeyId());
+ targetFtp.setSystemKey(CryptogramUtil.doDecrypt(secretKeyDO.getPrivateKey()));
+ targetFtp.setPassword(CryptogramUtil.doDecrypt(secretKeyDO.getPassword()));
+ }
+ Sftp uploadSftp = getSftp(targetFtp);
+ // 2.1 上传
+ String suffix = FileUtil.getSuffix(srcPath);
+ String fileName = imageDo.getName() + "." + suffix;
+ ByteArrayInputStream arrayInputStream = new ByteArrayInputStream(byteOut.toByteArray()); //转换
+ String romPath = "/home/image/" + UUID.randomUUID()+"/";
+ uploadSftp.mkDirs(romPath);//递归创建
+ uploadSftp.upload(romPath, fileName, arrayInputStream);
+ uploadSftp.close();
+ return null;
+ }
+
+ /**
+ *
+ * 获取Sftp连接
+ * @param config 连接配置
+ * @return
+ */
+ private Sftp getSftp(FtpConfig config){
+ Session session;
+ if (Objects.nonNull(config.getSystemKey())) {
+ session = JschUtil.getSession(config.getHost(), config.getPort(), config.getUser(), config.getSystemKey().getBytes(StandardCharsets.UTF_8), config.getPassword().getBytes());
+ } else {
+ session = JschUtil.getSession(config.getHost(), config.getPort(), config.getUser(), config.getPassword());
+ }
+ return new Sftp(session);
+ }
}