diff --git a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java index 6b12efe5..3c56ac5b 100644 --- a/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java +++ b/orion-ops-framework/orion-ops-framework-common/src/main/java/com/orion/ops/framework/common/constant/ErrorMessage.java @@ -13,6 +13,8 @@ public interface ErrorMessage { String PARAM_MISSING = "参数不能为空"; + String PARAM_ERROR = "参数错误"; + String ID_MISSING = "id 不能为空"; String INVALID_PARAM = "参数验证失败"; @@ -91,4 +93,6 @@ public interface ErrorMessage { String FILE_READ_ERROR = "文件读取失败"; + String PLEASE_CHECK_HOST_SSH = "请检查主机 {} 是否存在/权限/SSH配置"; + } diff --git a/orion-ops-framework/orion-ops-spring-boot-starter-job/src/main/java/com/orion/ops/framework/job/core/utils/QuartzUtils.java b/orion-ops-framework/orion-ops-spring-boot-starter-job/src/main/java/com/orion/ops/framework/job/core/utils/QuartzUtils.java index 57aba50e..08716175 100644 --- a/orion-ops-framework/orion-ops-spring-boot-starter-job/src/main/java/com/orion/ops/framework/job/core/utils/QuartzUtils.java +++ b/orion-ops-framework/orion-ops-spring-boot-starter-job/src/main/java/com/orion/ops/framework/job/core/utils/QuartzUtils.java @@ -1,9 +1,10 @@ package com.orion.ops.framework.job.core.utils; import com.orion.lang.utils.Exceptions; +import com.orion.lang.utils.Objects1; import com.orion.lang.utils.collect.Maps; +import com.orion.ops.framework.common.constant.FieldConst; import org.quartz.*; -import org.quartz.spi.MutableTrigger; import java.util.Map; @@ -16,6 +17,10 @@ import java.util.Map; */ public class QuartzUtils { + private static final String JOB_PREFIX = "Job_"; + + private static final String TRIGGER_PREFIX = "Trigger_"; + private static Scheduler scheduler; private QuartzUtils() { @@ -24,39 +29,48 @@ public class QuartzUtils { /** * 添加任务 * - * @param name name - * @param group group + * @param type type + * @param key key * @param cron cron + * @param desc desc * @param jobClass jobClass */ - public static void addJob(String name, String group, - String cron, Class jobClass) { - QuartzUtils.addJob(name, group, - cron, jobClass, - Maps.empty()); + public static void addJob(String type, Object key, + String cron, String desc, + Class jobClass) { + QuartzUtils.addJob(type, key, + cron, desc, + jobClass, Maps.newMap()); } /** * 添加任务 * - * @param name name - * @param group group + * @param type type + * @param key key * @param cron cron + * @param desc desc * @param jobClass jobClass * @param params params */ - public static void addJob(String name, String group, - String cron, Class jobClass, - Map params) { + public static void addJob(String type, Object key, + String cron, String desc, + Class jobClass, + Map params) { + params.put(FieldConst.KEY, key); // 生成 job JobDetail jobDetail = JobBuilder.newJob(jobClass) - .withIdentity(name, group) + .withDescription(desc) + .withIdentity(getJobKey(type, key)) .usingJobData(new JobDataMap(params)) .storeDurably() .build(); // 生成触发器 - MutableTrigger trigger = CronScheduleBuilder.cronSchedule(cron) - .withMisfireHandlingInstructionDoNothing() + Trigger trigger = TriggerBuilder.newTrigger() + .withIdentity(getTriggerKey(type, key)) + .withSchedule(CronScheduleBuilder + .cronSchedule(cron) + .withMisfireHandlingInstructionIgnoreMisfires()) .build(); QuartzUtils.addJob(jobDetail, trigger); } @@ -71,66 +85,100 @@ public class QuartzUtils { try { scheduler.scheduleJob(jobDetail, trigger); } catch (Exception e) { - throw Exceptions.task(); + throw Exceptions.task(e); } } /** * 删除任务 * - * @param name name - * @param group group + * @param type type + * @param key key */ - public static void deleteJob(String name, String group) { + public static void deleteJob(String type, Object key) { try { - scheduler.deleteJob(new JobKey(name, group)); + scheduler.deleteJob(getJobKey(type, key)); } catch (Exception e) { - throw Exceptions.task(); + throw Exceptions.task(e); } } /** * 暂停任务 * - * @param name name - * @param group group + * @param type type + * @param key key */ - public static void pauseJob(String name, String group) { + public static void pauseJob(String type, Object key) { try { - scheduler.pauseJob(new JobKey(name, group)); + scheduler.pauseJob(getJobKey(type, key)); } catch (Exception e) { - throw Exceptions.task(); + throw Exceptions.task(e); } } /** * 恢复任务 * - * @param name name - * @param group group + * @param type type + * @param key key */ - public static void resumeJob(String name, String group) { + public static void resumeJob(String type, Object key) { try { - scheduler.resumeJob(new JobKey(name, group)); + scheduler.resumeJob(getJobKey(type, key)); } catch (Exception e) { - throw Exceptions.task(); + throw Exceptions.task(e); } } /** * 立即执行任务 * - * @param name name - * @param group group + * @param type type + * @param key key */ - public static void triggerJob(String name, String group) { + public static void triggerJob(String type, Object key) { + triggerJob(type, key, Maps.newMap()); + } + + /** + * 立即执行任务 + * + * @param type type + * @param key key + * @param params params + */ + public static void triggerJob(String type, Object key, Map params) { try { - scheduler.triggerJob(new JobKey(name, group)); + params.put(FieldConst.KEY, key); + scheduler.triggerJob(getJobKey(type, key), new JobDataMap(params)); } catch (Exception e) { - throw Exceptions.task(); + throw Exceptions.task(e); } } + /** + * 获取 jobKey + * + * @param type type + * @param key key + * @return jobKey + */ + private static JobKey getJobKey(String type, Object key) { + return new JobKey(JOB_PREFIX + type + "_" + Objects1.toString(key), JOB_PREFIX + type); + } + + /** + * 获取 triggerKey + * + * @param type type + * @param key key + * @return triggerKey + */ + private static TriggerKey getTriggerKey(String type, Object key) { + return new TriggerKey(TRIGGER_PREFIX + type + "_" + Objects1.toString(key), TRIGGER_PREFIX + type); + } + /** * 设置调度器 * diff --git a/orion-ops-launch/src/main/resources/application.yaml b/orion-ops-launch/src/main/resources/application.yaml index 0c13a68b..8d9bb076 100644 --- a/orion-ops-launch/src/main/resources/application.yaml +++ b/orion-ops-launch/src/main/resources/application.yaml @@ -68,7 +68,7 @@ spring: job-store-type: JDBC overwrite-existing-jobs: false jdbc: - initialize-schema: ALWAYS + initialize-schema: NEVER properties: org: quartz: diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.http b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.http index b185445f..4387b9ff 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.http +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.http @@ -4,13 +4,12 @@ Content-Type: application/json Authorization: {{token}} { - "name": "", - "expression": "", - "timeout": "", - "command": "", - "parameterSchema": "", - "status": "", - "recentLogId": "" + "name": "测试 1", + "expression": "0 */3 * * * ?", + "timeout": "0", + "command": "echo 123", + "parameterSchema": "[]", + "hostIdList": [1] } @@ -19,15 +18,27 @@ PUT {{baseUrl}}/asset/exec-job/update Content-Type: application/json Authorization: {{token}} +{ + "id": 5, + "name": "测试 1", + "expression": "0 */1 * * * ?", + "timeout": "0", + "command": "echo 123", + "parameterSchema": "[]", + "hostIdList": [ + 1 + ] +} + + +### 更新计划执行任务状态 +PUT {{baseUrl}}/asset/exec-job/update-status +Content-Type: application/json +Authorization: {{token}} + { "id": "", - "name": "", - "expression": "", - "timeout": "", - "command": "", - "parameterSchema": "", - "status": "", - "recentLogId": "" + "status": "" } @@ -36,28 +47,6 @@ GET {{baseUrl}}/asset/exec-job/get?id=1 Authorization: {{token}} -### 批量查询计划执行任务 -GET {{baseUrl}}/asset/exec-job/batch-get?idList=1,2,3 -Authorization: {{token}} - - -### 查询全部计划执行任务 -POST {{baseUrl}}/asset/exec-job/list -Content-Type: application/json -Authorization: {{token}} - -{ - "id": "", - "name": "", - "expression": "", - "timeout": "", - "command": "", - "parameterSchema": "", - "status": "", - "recentLogId": "" -} - - ### 分页查询计划执行任务 POST {{baseUrl}}/asset/exec-job/query Content-Type: application/json @@ -68,12 +57,8 @@ Authorization: {{token}} "limit": 10, "id": "", "name": "", - "expression": "", - "timeout": "", "command": "", - "parameterSchema": "", - "status": "", - "recentLogId": "" + "status": "" } @@ -82,8 +67,4 @@ DELETE {{baseUrl}}/asset/exec-job/delete?id=1 Authorization: {{token}} -### 批量删除计划执行任务 -DELETE {{baseUrl}}/asset/exec-job/batch-delete?idList=1,2,3 -Authorization: {{token}} - ### diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.java index 23ebedd8..7a9316cf 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/controller/ExecJobController.java @@ -39,13 +39,6 @@ import javax.annotation.Resource; @SuppressWarnings({"ELValidationInJSP", "SpringElInspection"}) public class ExecJobController { - - // TODO EXEC_seq - // todo 测试一下添加失败 操作日志是怎么 - // TODO 操作日志 菜单 - // TODO 手动执行 - // TODO NEXT time - @Resource private ExecJobService execJobService; diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/dao/ExecJobDAO.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/dao/ExecJobDAO.java index 6330d839..16a68a18 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/dao/ExecJobDAO.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/dao/ExecJobDAO.java @@ -1,9 +1,9 @@ package com.orion.ops.module.asset.dao; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.orion.ops.framework.mybatis.core.mapper.IMapper; import com.orion.ops.module.asset.entity.domain.ExecJobDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; /** * 计划执行任务 Mapper 接口 @@ -16,21 +16,10 @@ import org.apache.ibatis.annotations.Mapper; public interface ExecJobDAO extends IMapper { /** - * 获取查询条件 + * 自增 exec_seq * - * @param entity entity - * @return 查询条件 + * @param id id */ - default LambdaQueryWrapper queryCondition(ExecJobDO entity) { - return this.wrapper() - .eq(ExecJobDO::getId, entity.getId()) - .eq(ExecJobDO::getName, entity.getName()) - .eq(ExecJobDO::getExpression, entity.getExpression()) - .eq(ExecJobDO::getTimeout, entity.getTimeout()) - .eq(ExecJobDO::getCommand, entity.getCommand()) - .eq(ExecJobDO::getParameterSchema, entity.getParameterSchema()) - .eq(ExecJobDO::getStatus, entity.getStatus()) - .eq(ExecJobDO::getRecentLogId, entity.getRecentLogId()); - } + void incrExecSeq(@Param("id") Long id); } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/ExecJobOperatorType.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/ExecJobOperatorType.java index d5d9668a..ca46cb50 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/ExecJobOperatorType.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/define/operator/ExecJobOperatorType.java @@ -1,4 +1,4 @@ - package com.orion.ops.module.asset.define.operator; +package com.orion.ops.module.asset.define.operator; import com.orion.ops.framework.biz.operator.log.core.annotation.Module; import com.orion.ops.framework.biz.operator.log.core.factory.InitializingOperatorTypes; @@ -30,9 +30,9 @@ public class ExecJobOperatorType extends InitializingOperatorTypes { public OperatorType[] types() { return new OperatorType[]{ new OperatorType(L, CREATE, "创建计划任务 ${name}"), + new OperatorType(M, UPDATE, "更新计划任务 ${before}"), + new OperatorType(M, UPDATE_STATUS, "${statusName}计划任务 ${name}"), new OperatorType(M, EXEC, "手动执行计划任务 ${name}"), - new OperatorType(M, UPDATE, "更新计划任务 ${name}"), - new OperatorType(M, UPDATE_STATUS, "更新计划任务状态 ${name} ${statusName}"), new OperatorType(H, DELETE, "删除计划任务 ${name}"), }; } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/exec/ExecJobQueryRequest.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/exec/ExecJobQueryRequest.java index b627fcdc..428d72a7 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/exec/ExecJobQueryRequest.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/exec/ExecJobQueryRequest.java @@ -34,4 +34,7 @@ public class ExecJobQueryRequest extends PageRequest { @Schema(description = "启用状态 0禁用 1启用") private Integer status; + @Schema(description = "是否查询最近执行任务") + private Boolean queryRecentLog; + } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/ExecJobVO.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/ExecJobVO.java index d97b1833..52e15292 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/ExecJobVO.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/ExecJobVO.java @@ -8,6 +8,7 @@ import lombok.NoArgsConstructor; import java.io.Serializable; import java.util.Date; +import java.util.List; /** * 计划执行任务 视图响应对象 @@ -31,9 +32,6 @@ public class ExecJobVO implements Serializable { @Schema(description = "任务名称") private String name; - @Schema(description = "执行序列") - private Integer execSeq; - @Schema(description = "cron 表达式") private String expression; @@ -52,16 +50,19 @@ public class ExecJobVO implements Serializable { @Schema(description = "最近执行id") private Long recentLogId; + @Schema(description = "最近执行状态") + private String recentExecStatus; + + @Schema(description = "最近执行时间") + private Date recentExecTime; + @Schema(description = "创建时间") private Date createTime; @Schema(description = "修改时间") private Date updateTime; - @Schema(description = "创建人") - private String creator; - - @Schema(description = "修改人") - private String updater; + @Schema(description = "执行主机") + private List hostIdList; } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/enums/ExecJobStatusEnum.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/enums/ExecJobStatusEnum.java index 03fd711e..bbbe7afa 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/enums/ExecJobStatusEnum.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/enums/ExecJobStatusEnum.java @@ -17,17 +17,19 @@ public enum ExecJobStatusEnum { /** * 停用 */ - DISABLED(0), + DISABLED(0, "停用"), /** * 启用 */ - ENABLED(1), + ENABLED(1, "启用"), ; private final Integer status; + private final String statusName; + public static ExecJobStatusEnum of(Integer status) { if (status == null) { return null; diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/ExecJobService.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/ExecJobService.java index 5dddbf8c..d674eab7 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/ExecJobService.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/ExecJobService.java @@ -56,6 +56,14 @@ public interface ExecJobService { */ DataGrid getExecJobPage(ExecJobQueryRequest request); + /** + * 获取下一个执行序列 + * + * @param id id + * @return seq + */ + Integer getNextExecSeq(Long id); + /** * 删除计划执行任务 * diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobHostServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobHostServiceImpl.java index d2337d24..877ce900 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobHostServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobHostServiceImpl.java @@ -1,6 +1,5 @@ package com.orion.ops.module.asset.service.impl; -import com.orion.lang.utils.collect.Lists; import com.orion.ops.module.asset.dao.ExecJobHostDAO; import com.orion.ops.module.asset.entity.domain.ExecJobHostDO; import com.orion.ops.module.asset.service.ExecJobHostService; @@ -30,16 +29,14 @@ public class ExecJobHostServiceImpl implements ExecJobHostService { log.info("ExecJobHostService.setHostIdByJobId jobId: {}, hostIdList: {}", jobId, hostIdList); // 删除 execJobHostDAO.deleteByJobId(jobId); - // 如果不为空则重新插入 - if (!Lists.isEmpty(hostIdList)) { - List rows = hostIdList.stream() - .map(s -> ExecJobHostDO.builder() - .hostId(s) - .jobId(jobId) - .build()) - .collect(Collectors.toList()); - execJobHostDAO.insertBatch(rows); - } + // 重新插入 + List rows = hostIdList.stream() + .map(s -> ExecJobHostDO.builder() + .hostId(s) + .jobId(jobId) + .build()) + .collect(Collectors.toList()); + execJobHostDAO.insertBatch(rows); } @Override diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobServiceImpl.java index e8660e2d..4f36865c 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/ExecJobServiceImpl.java @@ -3,21 +3,43 @@ package com.orion.ops.module.asset.service.impl; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.orion.lang.define.wrapper.DataGrid; +import com.orion.lang.utils.Booleans; +import com.orion.lang.utils.Strings; +import com.orion.lang.utils.time.Dates; +import com.orion.lang.utils.time.cron.Cron; +import com.orion.ops.framework.biz.operator.log.core.utils.OperatorLogs; import com.orion.ops.framework.common.constant.ErrorMessage; +import com.orion.ops.framework.common.constant.FieldConst; import com.orion.ops.framework.common.utils.Valid; +import com.orion.ops.framework.job.core.utils.QuartzUtils; +import com.orion.ops.framework.security.core.utils.SecurityUtils; import com.orion.ops.module.asset.convert.ExecJobConvert; import com.orion.ops.module.asset.dao.ExecJobDAO; +import com.orion.ops.module.asset.dao.ExecLogDAO; import com.orion.ops.module.asset.entity.domain.ExecJobDO; +import com.orion.ops.module.asset.entity.domain.ExecLogDO; import com.orion.ops.module.asset.entity.request.exec.ExecJobCreateRequest; import com.orion.ops.module.asset.entity.request.exec.ExecJobQueryRequest; import com.orion.ops.module.asset.entity.request.exec.ExecJobUpdateRequest; import com.orion.ops.module.asset.entity.request.exec.ExecJobUpdateStatusRequest; import com.orion.ops.module.asset.entity.vo.ExecJobVO; +import com.orion.ops.module.asset.enums.ExecJobStatusEnum; +import com.orion.ops.module.asset.enums.HostConfigTypeEnum; +import com.orion.ops.module.asset.service.AssetAuthorizedDataService; +import com.orion.ops.module.asset.service.ExecJobHostService; import com.orion.ops.module.asset.service.ExecJobService; import lombok.extern.slf4j.Slf4j; +import org.quartz.Job; +import org.quartz.JobExecutionContext; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.function.Function; +import java.util.stream.Collectors; /** * 计划执行任务 服务实现类 @@ -30,30 +52,57 @@ import javax.annotation.Resource; @Service public class ExecJobServiceImpl implements ExecJobService { + // TODO 测试 SSH 禁用后是什么样子的 + // TODO 操作日志 菜单 + // TODO 执行日志抽象 + // TODO 任务分组 + // TODO 手动执行 测试 quartz + + private static final String QUARTZ_TYPE = "Exec"; + @Resource private ExecJobDAO execJobDAO; + @Resource + private ExecJobHostService execJobHostService; + + @Resource + private ExecLogDAO execLogDAO; + + @Resource + private AssetAuthorizedDataService assetAuthorizedDataService; + @Override + @Transactional(rollbackFor = Exception.class) public Long createExecJob(ExecJobCreateRequest request) { log.info("ExecJobService-createExecJob request: {}", JSON.toJSONString(request)); + // 验证表达式是否正确 + Cron.of(request.getExpression()); // 转换 ExecJobDO record = ExecJobConvert.MAPPER.to(request); // 查询数据是否冲突 this.checkExecJobPresent(record); - // TODO 查询主机是否存在 - // 查询是否有主机权限 - // 插入 + // 查询主机是否有权限 + this.checkHostPermission(request.getHostIdList()); + // 插入任务 + record.setStatus(ExecJobStatusEnum.ENABLED.getStatus()); int effect = execJobDAO.insert(record); Long id = record.getId(); - // TODO 插入主机 + // 设置任务主机 + execJobHostService.setHostIdByJobId(id, request.getHostIdList()); + // 设置 quartz 状态 + this.setQuartzJobStatus(record, false, true); log.info("ExecJobService-createExecJob id: {}, effect: {}", id, effect); return id; } @Override + @Transactional(rollbackFor = Exception.class) public Integer updateExecJobById(ExecJobUpdateRequest request) { Long id = Valid.notNull(request.getId(), ErrorMessage.ID_MISSING); log.info("ExecJobService-updateExecJobById id: {}, request: {}", id, JSON.toJSONString(request)); + // 验证表达式是否正确 + Cron.of(request.getExpression()); // 查询 ExecJobDO record = execJobDAO.selectById(id); Valid.notNull(record, ErrorMessage.DATA_ABSENT); @@ -61,44 +110,120 @@ public class ExecJobServiceImpl implements ExecJobService { ExecJobDO updateRecord = ExecJobConvert.MAPPER.to(request); // 查询数据是否冲突 this.checkExecJobPresent(updateRecord); - // 更新 + // 查询主机是否有权限 + this.checkHostPermission(request.getHostIdList()); + // 更新任务 int effect = execJobDAO.updateById(updateRecord); + // 设置任务主机 + execJobHostService.setHostIdByJobId(id, request.getHostIdList()); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.BEFORE, record.getName()); + // 设置 quartz 状态 + this.setQuartzJobStatus(updateRecord, true, ExecJobStatusEnum.ENABLED.getStatus().equals(record.getStatus())); log.info("ExecJobService-updateExecJobById effect: {}", effect); return effect; } @Override + @Transactional(rollbackFor = Exception.class) public Integer updateExecJobStatus(ExecJobUpdateStatusRequest request) { - return null; + Long id = request.getId(); + ExecJobStatusEnum status = ExecJobStatusEnum.of(request.getStatus()); + Valid.notNull(status, ErrorMessage.PARAM_ERROR); + log.info("ExecJobService-updateExecJobStatus id: {}, status: {}", id, status); + // 查询任务 + ExecJobDO record = execJobDAO.selectById(id); + Valid.notNull(record, ErrorMessage.DATA_ABSENT); + // 更新状态 + ExecJobDO update = new ExecJobDO(); + update.setId(id); + update.setStatus(status.getStatus()); + int effect = execJobDAO.updateById(update); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.NAME, record.getName()); + OperatorLogs.add(OperatorLogs.STATUS_NAME, status.getStatusName()); + // 设置 quartz 状态 + this.setQuartzJobStatus(record, true, ExecJobStatusEnum.ENABLED.equals(status)); + return effect; } @Override public ExecJobVO getExecJobById(Long id) { - // 查询 + // 查询任务 ExecJobDO record = execJobDAO.selectById(id); Valid.notNull(record, ErrorMessage.DATA_ABSENT); // 转换 - return ExecJobConvert.MAPPER.to(record); + ExecJobVO vo = ExecJobConvert.MAPPER.to(record); + // 查询任务主机 + List hostIdList = execJobHostService.getHostIdByJobId(id); + vo.setHostIdList(hostIdList); + return vo; } @Override public DataGrid getExecJobPage(ExecJobQueryRequest request) { // 条件 LambdaQueryWrapper wrapper = this.buildQueryWrapper(request); - // 查询 - return execJobDAO.of(wrapper) + // 查询任务 + DataGrid dataGrid = execJobDAO.of(wrapper) .page(request) .dataGrid(ExecJobConvert.MAPPER::to); + if (!Booleans.isTrue(request.getQueryRecentLog())) { + return dataGrid; + } + // 查询最近执行任务 + List logIdList = dataGrid.stream() + .map(ExecJobVO::getRecentLogId) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + if (!logIdList.isEmpty()) { + List logList = execLogDAO.selectBatchIds(logIdList); + Map logMap = logList.stream() + .collect(Collectors.toMap(ExecLogDO::getId, Function.identity())); + dataGrid.forEach(s -> { + Long logId = s.getRecentLogId(); + if (logId == null) { + return; + } + ExecLogDO execLog = logMap.get(logId); + if (execLog == null) { + return; + } + s.setRecentExecTime(execLog.getStartTime()); + s.setRecentExecStatus(execLog.getStatus()); + }); + } + return dataGrid; } @Override + public Integer getNextExecSeq(Long id) { + // 自增 + execJobDAO.incrExecSeq(id); + // 获取 + return execJobDAO.of() + .createWrapper() + .select(ExecJobDO::getExecSeq) + .eq(ExecJobDO::getId, id) + .then() + .getOne(ExecJobDO::getExecSeq); + } + + @Override + @Transactional(rollbackFor = Exception.class) public Integer deleteExecJobById(Long id) { log.info("ExecJobService-deleteExecJobById id: {}", id); // 检查数据是否存在 ExecJobDO record = execJobDAO.selectById(id); Valid.notNull(record, ErrorMessage.DATA_ABSENT); - // 删除 + // 删除任务 int effect = execJobDAO.deleteById(id); + // 删除任务主机 + effect += execJobHostService.deleteByJobId(id); + // 设置日志参数 + OperatorLogs.add(OperatorLogs.NAME, record.getName()); + // 设置 quartz 状态 + this.setQuartzJobStatus(record, true, false); log.info("ExecJobService-deleteExecJobById id: {}, effect: {}", id, effect); return effect; } @@ -135,4 +260,48 @@ public class ExecJobServiceImpl implements ExecJobService { .orderByDesc(ExecJobDO::getId); } + /** + * 设置 quartz 任务状态 + * + * @param record record + * @param delete 是否删除 + * @param add 是否新增 + */ + private void setQuartzJobStatus(ExecJobDO record, boolean delete, boolean add) { + Long id = record.getId(); + // 删除 quartz job + if (delete) { + QuartzUtils.deleteJob(QUARTZ_TYPE, id); + } + // FIXME + // 启动 quartz job + if (add) { + QuartzUtils.addJob(QUARTZ_TYPE, id, record.getExpression(), record.getName(), TestJob.class); + } + } + + /** + * 检查主机权限 + * + * @param hostIdList hostIdList + */ + private void checkHostPermission(List hostIdList) { + // 查询有权限的主机 + List authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostId(SecurityUtils.getLoginUserId(), HostConfigTypeEnum.SSH); + for (Long hostId : hostIdList) { + Valid.isTrue(authorizedHostIdList.contains(hostId), Strings.format(ErrorMessage.PLEASE_CHECK_HOST_SSH, hostId)); + } + } + + // FIXME + static class TestJob implements Job { + + @Override + public void execute(JobExecutionContext context) { + System.out.println("----------------------"); + System.out.println(Dates.current()); + System.out.println(context.getMergedJobDataMap().getLong(FieldConst.KEY)); + } + } + } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostServiceImpl.java index e3f327ff..ef97f3ec 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/HostServiceImpl.java @@ -21,6 +21,7 @@ import com.orion.ops.module.asset.entity.request.host.HostCreateRequest; import com.orion.ops.module.asset.entity.request.host.HostQueryRequest; import com.orion.ops.module.asset.entity.request.host.HostUpdateRequest; import com.orion.ops.module.asset.entity.vo.HostVO; +import com.orion.ops.module.asset.service.ExecJobHostService; import com.orion.ops.module.asset.service.HostConfigService; import com.orion.ops.module.asset.service.HostService; import com.orion.ops.module.infra.api.DataExtraApi; @@ -66,6 +67,9 @@ public class HostServiceImpl implements HostService { @Resource private HostConfigService hostConfigService; + @Resource + private ExecJobHostService execJobHostService; + @Resource private TagRelApi tagRelApi; @@ -210,8 +214,11 @@ public class HostServiceImpl implements HostService { @Override @Async("asyncExecutor") public void deleteHostRelByIdAsync(Long id) { - // 删除配置 + log.info("HostService-deleteHostRelByIdAsync id: {}", id); + // 删除主机配置 hostConfigDAO.deleteByHostId(id); + // 删除计划执行任务主机 + execJobHostService.deleteByHostId(id); // 删除分组 dataGroupRelApi.deleteByRelId(DataGroupTypeEnum.HOST, id); // 删除 tag 引用 diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecJobMapper.xml b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecJobMapper.xml index ecc3cd0e..7b3e2c58 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecJobMapper.xml +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecJobMapper.xml @@ -6,6 +6,7 @@ + @@ -21,7 +22,13 @@ - id, name, expression, timeout, command, parameter_schema, status, recent_log_id, create_time, update_time, creator, updater, deleted + id, name, exec_seq, expression, timeout, command, parameter_schema, status, recent_log_id, create_time, update_time, creator, updater, deleted + + UPDATE exec_job + SET exec_seq = exec_seq + 1 + WHERE id = #{id} + + diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecLogMapper.xml b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecLogMapper.xml index 993c36e9..ce4c131e 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecLogMapper.xml +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/resources/mapper/ExecLogMapper.xml @@ -10,6 +10,7 @@ + @@ -25,7 +26,7 @@ - id, user_id, username, source, source_id, description, command, parameter_schema, timeout, status, start_time, finish_time, create_time, update_time, creator, updater, deleted + id, user_id, username, source, source_id, description, exec_seq, command, parameter_schema, timeout, status, start_time, finish_time, create_time, update_time, creator, updater, deleted