diff --git a/react-ui/src/pages/Dataset/components/ResourceItem/index.less b/react-ui/src/pages/Dataset/components/ResourceItem/index.less deleted file mode 100644 index edd97f85..00000000 --- a/react-ui/src/pages/Dataset/components/ResourceItem/index.less +++ /dev/null @@ -1,61 +0,0 @@ -.resource-item { - position: relative; - width: calc(25% - 15px); - padding: 20px; - background: white; - border: 1px solid #eaeaea; - border-radius: 4px; - cursor: pointer; - - @media screen and (max-width: 1860px) { - & { - width: calc(33.33% - 13.33px); - } - } - - &__name { - position: relative; - display: inline-block; - height: 24px; - margin: 0 10px 0 0 !important; - color: @text-color; - font-size: 16px; - } - - &__description { - height: 44px; - margin-bottom: 20px; - color: @text-color-secondary; - font-size: 14px; - .multiLine(2); - } - &__time { - display: flex; - flex: 0 1 content; - align-items: center; - width: 100%; - color: #808080; - font-size: 13px; - } - - &:hover { - border-color: @primary-color; - box-shadow: 0px 0px 6px 1px rgba(0, 0, 0, 0.1); - - .resource-item__name { - color: @primary-color; - } - } -} - -.resource-item__name { - &::after { - position: absolute; - top: 14px; - left: 0; - width: 100%; - height: 6px; - background: linear-gradient(to right, rgba(22, 100, 255, 0.3) 0, rgba(22, 100, 255, 0) 100%); - content: ''; - } -} diff --git a/react-ui/src/pages/Dataset/components/ResourceItem/index.tsx b/react-ui/src/pages/Dataset/components/ResourceItem/index.tsx deleted file mode 100644 index 3b517184..00000000 --- a/react-ui/src/pages/Dataset/components/ResourceItem/index.tsx +++ /dev/null @@ -1,54 +0,0 @@ -import clock from '@/assets/img/clock.png'; -import creatByImg from '@/assets/img/creatBy.png'; -import KFIcon from '@/components/KFIcon'; -import { formatDate } from '@/utils/date'; -import { Button, Flex, Typography } from 'antd'; -import { ResourceData } from '../../config'; -import styles from './index.less'; - -type ResourceItemProps = { - item: ResourceData; - isPublic: boolean; - onRemove: (item: ResourceData) => void; - onClick: (item: ResourceData) => void; -}; - -function ResourceItem({ item, isPublic, onClick, onRemove }: ResourceItemProps) { - return ( -
onClick(item)}> - - - {item.name} - - {!isPublic && ( - - )} - -
{item.description}
- -
- - {item.create_by} -
-
- - 最近更新: {formatDate(item.update_time, 'YYYY-MM-DD')} -
-
-
- ); -} - -export default ResourceItem; diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java index b13c414d..591628a9 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/service/impl/ImageServiceImpl.java @@ -32,6 +32,7 @@ import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.util.Date; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CompletableFuture; @@ -85,6 +86,7 @@ public class ImageServiceImpl implements ImageService { private String pvcName; @Value("${jupyter.namespace}") private String namespace; + /** * 通过ID查询单条数据 * @@ -99,8 +101,8 @@ public class ImageServiceImpl implements ImageService { /** * 分页查询 * - * @param image 筛选条件 - * @param pageRequest 分页对象 + * @param image 筛选条件 + * @param pageRequest 分页对象 * @return 查询结果 */ @Override @@ -110,7 +112,6 @@ public class ImageServiceImpl implements ImageService { } - /** * 新增数据 * @@ -138,7 +139,7 @@ public class ImageServiceImpl implements ImageService { @Override public Image update(Image image) { int currentState = image.getState(); - if(currentState == 0){ + if (currentState == 0) { throw new RuntimeException("镜像已被删除,无法更新。"); } LoginUser loginUser = SecurityUtils.getLoginUser(); @@ -163,7 +164,7 @@ public class ImageServiceImpl implements ImageService { @Override public String removeById(Integer id) throws Exception { Image image = this.imageDao.queryById(id); - if (image == null){ + if (image == null) { throw new Exception("镜像不存在"); } @@ -173,14 +174,20 @@ public class ImageServiceImpl implements ImageService { String createdBy = image.getCreateBy(); - if (!(StringUtils.equals(username,"admin") || !StringUtils.equals(username,createdBy))){ + if (!(StringUtils.equals(username, "admin") || !StringUtils.equals(username, createdBy))) { throw new Exception("无权限删除该镜像"); } - if (!imageVersionService.queryByImageId(id).isEmpty()){ - throw new Exception("请先删除该镜像下的版本文件"); +// if (!imageVersionService.queryByImageId(id).isEmpty()){ +// throw new Exception("请先删除该镜像下的版本文件"); +// } + List imageVersions = imageVersionService.queryByImageId(id); + + for (ImageVersion imageVersion : imageVersions) { + dockerClientUtil.removeImage(imageVersion.getUrl(), imageVersion.getHostIp()); } + image.setState(0); - return this.imageDao.update(image)>0?"删除成功":"删除失败"; + return this.imageDao.update(image) > 0 ? "删除成功" : "删除失败"; } @@ -207,7 +214,7 @@ public class ImageServiceImpl implements ImageService { public String insertImageAndVersion(ImageVo imageVo) throws Exception { Image existingImage = getByName(imageVo.getName()); Image imageToUse; - if(existingImage == null) { + if (existingImage == null) { // 如果不存在相同名称的镜像,则创建新的镜像记录 Image newImage = new Image(); newImage.setName(imageVo.getName()); @@ -217,7 +224,7 @@ public class ImageServiceImpl implements ImageService { if (imageToUse == null) { throw new Exception("新增镜像失败"); } - }else{ + } else { // 如果已存在相同名称的镜像,使用已存在的镜像 imageToUse = existingImage; } @@ -235,9 +242,9 @@ public class ImageServiceImpl implements ImageService { CompletableFuture.supplyAsync(() -> { Map resultMap = new HashMap<>(); try { - if(imageVo.getUploadType()==0){ - resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); - }else{ + if (imageVo.getUploadType() == 0) { + resultMap = createImageFromNet(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); + } else { resultMap = createImageFromLocal(imageVo.getName(), imageVo.getTagName(), imageVo.getPath()); } } catch (Exception e) { @@ -246,7 +253,7 @@ public class ImageServiceImpl implements ImageService { throw new RuntimeException("镜像构建失败: " + e.getMessage(), e); } return resultMap; - }).thenAccept(resultMap ->{ + }).thenAccept(resultMap -> { try { String imageUrl = resultMap.get("url"); String fileSize = resultMap.get("fileSize"); @@ -272,27 +279,27 @@ public class ImageServiceImpl implements ImageService { // 得到容器 V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); if (pod == null) { - String podName = deploymentName+"-"+ DateUtils.formatYMD10(new Date()); - pod = k8sClientUtil.createPodWithEnv(podName,serviceNS,proxyUrl,mountPath,pvcName,image); + String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); + pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); } - String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; + String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 - String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); + String loginlog = k8sClientUtil.executeCommand(pod, loginCmd); // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag String username = SecurityUtils.getLoginUser().getUsername(); // - String logs2 = k8sClientUtil.executeCommand(pod,"docker pull "+ netPath); + String logs2 = k8sClientUtil.executeCommand(pod, "docker pull " + netPath); // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag - if (StringUtils.isNoneBlank(logs2)){ + if (StringUtils.isNoneBlank(logs2)) { String[] lines = logs2.split("\n"); String lastLine = lines[lines.length - 1].trim(); String tagCmd = "docker tag " + lastLine + " " + harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; String imageUrl = harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; - String pushCmd = "docker push " + imageUrl; + String pushCmd = "docker push " + imageUrl; String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; String s = k8sClientUtil.executeCommand(pod, tagCmd); - if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ + if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))) { resultMap.put("url", imageUrl); //得到镜像文件大小 String imageSizeStr = k8sClientUtil.executeCommand(pod, sizeCmd); @@ -301,10 +308,10 @@ public class ImageServiceImpl implements ImageService { resultMap.put("fileSize", formattedImageSize); return resultMap; - }else { + } else { throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); } - }else { + } else { throw new Exception("拉取公网镜像失败,请检查网络或者镜像地址"); } } @@ -315,27 +322,27 @@ public class ImageServiceImpl implements ImageService { // 得到容器 V1Pod pod = k8sClientUtil.getNSPodList(serviceNS, deploymentName); if (pod == null) { - String podName = deploymentName+"-"+ DateUtils.formatYMD10(new Date()); - pod = k8sClientUtil.createPodWithEnv(podName,serviceNS,proxyUrl,mountPath,pvcName,image); + String podName = deploymentName + "-" + DateUtils.formatYMD10(new Date()); + pod = k8sClientUtil.createPodWithEnv(podName, serviceNS, proxyUrl, mountPath, pvcName, image); } - String loginCmd = "docker login -u " + harborUser +" -p "+harborpassword+" "+harborUrl; + String loginCmd = "docker login -u " + harborUser + " -p " + harborpassword + " " + harborUrl; // 执行命令 docker login -u admin -p Harbor12345 172.20.32.187 - String loginlog = k8sClientUtil.executeCommand(pod,loginCmd); + String loginlog = k8sClientUtil.executeCommand(pod, loginCmd); // 在这个容器的/data/admin 目录下执行命令 docker load -i fileName 得到返回的镜像名字name:tag String username = SecurityUtils.getLoginUser().getUsername(); // - String filePath = "/data/argo-workflow/" + bucketName + "/" +path; - String logs2 = k8sClientUtil.executeCommand(pod,"docker load -i "+filePath); + String filePath = "/data/argo-workflow/" + bucketName + "/" + path; + String logs2 = k8sClientUtil.executeCommand(pod, "docker load -i " + filePath); // 在容器里执行 docker tag name:tag nexus3.kube-system.svc:8083/imageName:imageTag - if (StringUtils.isNoneBlank(logs2)){ - String substring = logs2.substring(logs2.indexOf(":")+1).trim(); + if (StringUtils.isNoneBlank(logs2)) { + String substring = logs2.substring(logs2.indexOf(":") + 1).trim(); String tagCmd = "docker tag " + substring + " " + harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; String imageUrl = harborUrl + "/" + repository + "/" + username + "/" + imageName + ":" + imageTag; - String pushCmd = "docker push " + imageUrl; + String pushCmd = "docker push " + imageUrl; String sizeCmd = "docker inspect --format='{{.Size}}' " + imageUrl; String s = k8sClientUtil.executeCommand(pod, tagCmd); - if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))){ + if (StringUtils.isNotEmpty(k8sClientUtil.executeCommand(pod, pushCmd))) { resultMap.put("url", imageUrl); //得到镜像文件大小 String imageSizeStr = k8sClientUtil.executeCommand(pod, sizeCmd); @@ -343,43 +350,49 @@ public class ImageServiceImpl implements ImageService { String formattedImageSize = FileUtil.formatFileSize(sizeInBytes); // 格式化镜像文件大小 resultMap.put("fileSize", formattedImageSize); return resultMap; - }else { + } else { throw new Exception("解析镜像压缩包失败,请检查镜像文件"); } - }else { + } else { throw new Exception("解析镜像压缩包失败,请检查镜像文件"); } } - - @Override public Map uploadImageFiles(MultipartFile file) throws Exception { LoginUser loginUser = SecurityUtils.getLoginUser(); - String path = loginUser.getUsername()+"/"+file.getOriginalFilename(); + String path = loginUser.getUsername() + "/" + file.getOriginalFilename(); return minioService.uploadFile(bucketName, path, file); } @Override @Transactional + @Async public String saveImage(ImageVo imageVo) { - if(imageDao.getByName(imageVo.getName()) != null){ - throw new IllegalStateException("镜像名称已存在"); + Image oldImage = imageDao.getByName(imageVo.getName()); + if (oldImage != null) { + List oldImageVersions = imageVersionDao.queryByImageId(oldImage.getId()); + for (ImageVersion oldImageVersion : oldImageVersions) { + if(oldImageVersion.getTagName().equals(imageVo.getTagName())){ + throw new IllegalStateException("镜像tag不能重复"); + } + } } + LoginUser loginUser = SecurityUtils.getLoginUser(); String username = loginUser.getUsername().toLowerCase(); - String podName = username +"-editor-pod" + "-" + imageVo.getDevEnvironmentId().toString(); + String podName = username + "-editor-pod" + "-" + imageVo.getDevEnvironmentId().toString(); try { String containerId = k8sClientUtil.getPodContainerId(podName, namespace); String hostIp = k8sClientUtil.getHostIp(podName, namespace); - dockerClientUtil.commitImage(imageVo,containerId,hostIp,username); + dockerClientUtil.commitImage(imageVo, containerId, hostIp, username); HashMap resultMap = dockerClientUtil.pushImageToHorbor(imageVo, hostIp); Image image = new Image(); - BeanUtils.copyProperties(imageVo,image); + BeanUtils.copyProperties(imageVo, image); image.setImageType(Constant.Image_Type_Pri); image.setCreateBy(username); image.setUpdateBy(username); @@ -396,6 +409,7 @@ public class ImageServiceImpl implements ImageService { imageVersion.setFileSize(resultMap.get("size")); imageVersion.setCreateBy(username); imageVersion.setUpdateBy(username); + imageVersion.setHostIp(hostIp); imageVersion.setUpdateTime(new Date()); imageVersion.setCreateTime(new Date()); imageVersion.setState(1); @@ -410,7 +424,7 @@ public class ImageServiceImpl implements ImageService { return "保存镜像成功"; } catch (Exception e) { - throw new RuntimeException("保存镜像失败:" +e); + throw new RuntimeException("保存镜像失败:" + e); } } } diff --git a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DockerClientUtil.java b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DockerClientUtil.java index b20fa077..552b025a 100644 --- a/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DockerClientUtil.java +++ b/ruoyi-modules/management-platform/src/main/java/com/ruoyi/platform/utils/DockerClientUtil.java @@ -106,4 +106,9 @@ public class DockerClientUtil { } } + + public void removeImage(String imageName, String hostIp){ + DockerClient dockerClient = getDockerClient(hostIp); + dockerClient.removeImageCmd(imageName).withForce(true).exec(); + } } \ No newline at end of file