feat:(unify): 新增项目配置

This commit is contained in:
opensnail 2024-12-23 22:55:07 +08:00
parent 6810a46ec5
commit d06f86c3b2
18 changed files with 321 additions and 26 deletions

2
.gitignore vendored
View File

@ -33,3 +33,5 @@ target/
data/
rebel.xml
/sj-python-workspace/

View File

@ -529,3 +529,18 @@ CREATE TABLE `sj_workflow_task_batch`
) ENGINE = InnoDB
AUTO_INCREMENT = 0
DEFAULT CHARSET = utf8mb4 COMMENT ='工作流批次';
CREATE TABLE `sj_publish__config`
(
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '主键',
`namespace_id` VARCHAR(64) NOT NULL DEFAULT '764d604ec6fc45f68cd92514c40e9e1a' COMMENT '命名空间id',
`group_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '组名称',
`config_name` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '配置名称',
`config_value` varchar(512) NOT NULL DEFAULT '' COMMENT '配置值',
`create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`),
KEY `idx_namespace_id_group_name_config_name` (`namespace_id`, `group_name`, config_name),
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4 COMMENT ='发布配置';

View File

@ -0,0 +1,12 @@
package com.aizuda.snailjob.template.datasource.persistence.dataobject;
/**
* <p>
*
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
public class PublishConfigValueDO {
}

View File

@ -0,0 +1,13 @@
package com.aizuda.snailjob.template.datasource.persistence.mapper;
import com.aizuda.snailjob.template.datasource.persistence.po.PublishConfig;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
/**
* 发布配置
*
* @author opensnail
* @since 2024-12-22
*/
public interface PublishConfigMapper extends BaseMapper<PublishConfig> {
}

View File

@ -0,0 +1,46 @@
package com.aizuda.snailjob.template.datasource.persistence.po;
import com.aizuda.snailjob.template.datasource.persistence.dataobject.PublishConfigValueDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import lombok.Getter;
import lombok.Setter;
/**
* 告警通知接收人
*
* @author opensnail
* @since 2024-12-22
*/
@Getter
@Setter
@TableName("sj_notify_recipient")
public class PublishConfig extends CreateUpdateDt {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 命名空间id
*/
private String namespaceId;
/**
* 组名称
*/
private String groupName;
/**
* 配置名称
*/
private String configName;
/**
* 配置值 json存储
*/
@TableField(typeHandler = JacksonTypeHandler.class)
private PublishConfigValueDO configValue;
}

View File

@ -0,0 +1,18 @@
package com.aizuda.snailjob.server.web.constant;
import com.aizuda.snailjob.common.core.constant.SystemConstants;
import java.io.File;
public interface WebConstants extends SystemConstants {
String WORKDIR = System.getProperty("user.dir") + File.separator + "sj-python-workspace" + File.separator;
String DOCKER_FILE = "Dockerfile";
String DEFAULT_DOCKER_HOST = "unix:///var/run/docker.sock";
String WINDOWS_DEFAULT_DOCKER_HOST = "npipe:////./pipe/docker_engine";
}

View File

@ -22,6 +22,11 @@ import java.util.List;
public class DockerController {
private final DockerService dockerService;
@GetMapping("/status")
public boolean dockerStatus() {
return dockerService.dockerStatus();
}
@GetMapping("/container/page/list")
public PageResult<List<ContainerResponseVO>> getContainerList(ContainerQueryVO containerQueryVO) {
return dockerService.getContainerList(containerQueryVO);

View File

@ -1,11 +1,10 @@
package com.aizuda.snailjob.server.web.controller;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.net.NetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.http.HttpUtil;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.web.constant.WebConstants;
import com.aizuda.snailjob.server.web.model.enums.FileTypeEnum;
import com.aizuda.snailjob.server.web.model.request.InitProjectVO;
import com.aizuda.snailjob.server.web.model.response.FileVO;
@ -19,27 +18,22 @@ import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@RestController
@RequestMapping("/file")
@RequiredArgsConstructor
@Slf4j
public class FileViewerController {
private static final String workdir = System.getProperty("user.dir") + File.separator + "sj-python-workspace" + File.separator;
// 显示文件列表
@GetMapping("/files")
public List<FileVO> listFiles(@RequestParam(value = "directory") String directory) {
try {
// 读取目录下的文件列表
return Files.list(Paths.get(workdir + directory))
return Files.list(Paths.get(WebConstants.WORKDIR + directory))
.map(path -> {
File file = path.toFile();
FileVO fileVO = new FileVO();
@ -69,7 +63,7 @@ public class FileViewerController {
public ViewFileResponseVO viewFile(@RequestParam(value = "directory") String directory) {
try {
// 构建文件路径
String filePath = Paths.get(workdir + directory).toString();
String filePath = Paths.get(WebConstants.WORKDIR + directory).toString();
// 读取文件内容
String s = Files.readString(Paths.get(filePath));
@ -84,7 +78,17 @@ public class FileViewerController {
// 保存修改后的文件内容
@PutMapping
public Boolean saveFile(@RequestBody SaveFileRequestVO requestVO) {
FileUtil.writeUtf8String(requestVO.getContent().trim(), workdir + requestVO.getFileName());
String filePath = WebConstants.WORKDIR + requestVO.getFileName();
if (!FileUtil.isFile(filePath)) {
throw new SnailJobServerException("必须是文件才能更新", requestVO.getFileName());
}
try {
FileUtil.writeUtf8String(requestVO.getContent().trim(), WebConstants.WORKDIR + requestVO.getFileName());
} catch (Exception e) {
throw new SnailJobServerException("文件更新失败, 请选择需要更新文件的后点击更新");
}
return true;
}
@ -92,7 +96,7 @@ public class FileViewerController {
// https://github.com/open-snail/python-client/archive/refs/tags/v0.0.1.zip
public boolean initPythonProject(@RequestBody InitProjectVO initProjectVO) {
String projectPath = workdir + initProjectVO.getProjectName();
String projectPath = WebConstants.WORKDIR + initProjectVO.getGroupName();
boolean file = FileUtil.isFile(projectPath);
File mkdir;
if (!file) {

View File

@ -0,0 +1,48 @@
package com.aizuda.snailjob.server.web.controller;
import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.PublishConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.PublishConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.PublishConfigResponseVO;
import com.aizuda.snailjob.server.web.service.PublishConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* <p>
* 发布配置
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
@RestController
@RequestMapping("/publish-config")
@RequiredArgsConstructor
@Slf4j
public class PublishConfigController {
private final PublishConfigService publishConfigService;
@PostMapping
public boolean save(@RequestBody PublishConfigRequestVO requestVO) {
return publishConfigService.save(requestVO);
}
@PutMapping
public boolean update(@RequestBody PublishConfigRequestVO requestVO) {
return publishConfigService.update(requestVO);
}
@GetMapping("/{id}")
public PublishConfigResponseVO getDetail(@PathVariable("id") Long id) {
return publishConfigService.getById(id);
}
@GetMapping("/page/list")
public PageResult<List<PublishConfigResponseVO>> getPageList(PublishConfigQueryVO queryVO) {
return publishConfigService.getPageList(queryVO);
}
}

View File

@ -6,7 +6,7 @@ import lombok.Data;
@Data
public class InitProjectVO {
@NotBlank
private String projectName;
private String groupName;
@NotBlank
private String projectUrl;

View File

@ -0,0 +1,12 @@
package com.aizuda.snailjob.server.web.model.request;
/**
* <p>
*
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
public class PublishConfigQueryVO {
}

View File

@ -0,0 +1,12 @@
package com.aizuda.snailjob.server.web.model.request;
/**
* <p>
*
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
public class PublishConfigRequestVO {
}

View File

@ -0,0 +1,12 @@
package com.aizuda.snailjob.server.web.model.response;
/**
* <p>
*
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
public class PublishConfigResponseVO {
}

View File

@ -28,4 +28,6 @@ public interface DockerService {
boolean quickPublish(CreateContainerRequestVO requestVO);
PageResult<List<ImageResponseVO>> getImageList(ImageQueryVO imageQueryVO);
boolean dockerStatus();
}

View File

@ -0,0 +1,27 @@
package com.aizuda.snailjob.server.web.service;
import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.PublishConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.PublishConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.PublishConfigResponseVO;
import java.util.List;
/**
* <p>
* 发布配置
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
public interface PublishConfigService {
boolean save(PublishConfigRequestVO requestVO);
boolean update(PublishConfigRequestVO requestVO);
PublishConfigResponseVO getById(Long id);
PageResult<List<PublishConfigResponseVO>> getPageList(PublishConfigQueryVO queryVO);
}

View File

@ -1,9 +1,11 @@
package com.aizuda.snailjob.server.web.service.handler;
import com.aizuda.snailjob.server.web.constant.WebConstants;
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.apache.commons.lang3.SystemUtils;
import org.springframework.stereotype.Component;
@Component
@ -13,12 +15,9 @@ public class DockerHandler {
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/")
// todo ip换成服务器ip
.withDockerHost(SystemUtils.IS_OS_WINDOWS ? WebConstants.WINDOWS_DEFAULT_DOCKER_HOST : WebConstants.DEFAULT_DOCKER_HOST)
.withRegistryUrl("https://index.docker.io/v2/")
.build();
OkDockerHttpClient build = new OkDockerHttpClient.Builder()

View File

@ -5,6 +5,7 @@ import cn.hutool.core.lang.Assert;
import com.aizuda.snailjob.common.core.util.StreamUtils;
import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
import com.aizuda.snailjob.server.common.util.DateUtils;
import com.aizuda.snailjob.server.web.constant.WebConstants;
import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.base.SjBuildImageResultCallback;
import com.aizuda.snailjob.server.web.model.request.BuildImageRequestVO;
@ -22,10 +23,12 @@ import com.github.dockerjava.api.command.*;
import com.github.dockerjava.api.model.*;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.sun.jna.LastErrorException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@ -37,13 +40,13 @@ import static com.aizuda.snailjob.server.common.util.DateUtils.PURE_DATETIME_MS_
@RequiredArgsConstructor
public class DockerServiceImpl implements DockerService {
private final DockerHandler dockerHandler;
private static final String workdir = "/Users/zhangshuguang/snail-job-python";
private static final String workdir = WebConstants.WORKDIR;
@Override
public String buildImage(BuildImageRequestVO requestVO) {
String imageName = String.format("sj_%s_%s", requestVO.getGroupName(), DateUtils.toNowFormat(PURE_DATETIME_MS_PATTERN));
List<File> dockerfileList = FileUtil.loopFiles(workdir, pathname -> pathname.getName().equals("Dockerfile"));
List<File> dockerfileList = FileUtil.loopFiles(workdir + File.separator + requestVO.getGroupName(), pathname -> pathname.getName().equals(WebConstants.DOCKER_FILE));
Assert.isFalse(dockerfileList.isEmpty(), () -> new SnailJobServerException("不存在Dockerfile文件"));
Assert.isTrue(dockerfileList.size() == 1, () -> new SnailJobServerException("存在多个Dockerfile文件"));
@ -54,10 +57,17 @@ public class DockerServiceImpl implements DockerService {
private void buildImage(File file, String imageName) {
DockerClient dockerClient = dockerHandler.getDockerClient();
try {
BuildImageCmd imageCmd = dockerClient
.buildImageCmd(file)
.withTags(Sets.newHashSet(imageName));
imageCmd.exec(new SjBuildImageResultCallback()).awaitImageId();
} catch (Exception e) {
if (e.getCause() instanceof IOException) {
throw new SnailJobServerException("docker连接失败请确认Docker状态是否正常");
}
}
}
@Override
@ -76,7 +86,7 @@ public class DockerServiceImpl implements DockerService {
.withName(containerName)
.withEnv()
.withExposedPorts()
// .withHealthcheck()
.withHealthcheck(new HealthCheck())
// .withHostName(HostConfig)
.withLabels(labels)
@ -200,4 +210,15 @@ public class DockerServiceImpl implements DockerService {
return pageResult;
}
@Override
public boolean dockerStatus() {
try {
DockerClient dockerClient = dockerHandler.getDockerClient();
dockerClient.pingCmd().exec();
return true;
} catch (Exception e) {
return false;
}
}
}

View File

@ -0,0 +1,47 @@
package com.aizuda.snailjob.server.web.service.impl;
import com.aizuda.snailjob.server.web.model.base.PageResult;
import com.aizuda.snailjob.server.web.model.request.PublishConfigQueryVO;
import com.aizuda.snailjob.server.web.model.request.PublishConfigRequestVO;
import com.aizuda.snailjob.server.web.model.response.PublishConfigResponseVO;
import com.aizuda.snailjob.server.web.service.PublishConfigService;
import com.aizuda.snailjob.template.datasource.persistence.mapper.PublishConfigMapper;
import com.aizuda.snailjob.template.datasource.persistence.po.PublishConfig;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* <p>
* 发布配置
* </p>
*
* @author opensnail
* @date 2024-12-22
*/
@Service
@RequiredArgsConstructor
public class PublishConfigServiceImpl implements PublishConfigService {
private final PublishConfigMapper publishConfigMapper;
@Override
public boolean save(PublishConfigRequestVO requestVO) {
return 1 == publishConfigMapper.insert(new PublishConfig());
}
@Override
public boolean update(PublishConfigRequestVO requestVO) {
return false;
}
@Override
public PublishConfigResponseVO getById(Long id) {
return null;
}
@Override
public PageResult<List<PublishConfigResponseVO>> getPageList(PublishConfigQueryVO queryVO) {
return new PageResult<>();
}
}