🔨 批量执行.

This commit is contained in:
lijiahang
2024-03-13 14:49:47 +08:00
parent 97778f336f
commit 81ae46c181
21 changed files with 486 additions and 88 deletions

View File

@@ -41,4 +41,6 @@ public interface ExtraFieldConst extends FieldConst {
String HOST_NAME = "hostName";
String LOG_ID = "logId";
}

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.controller;
import com.orion.lang.define.wrapper.HttpWrapper;
import com.orion.ops.framework.biz.operator.log.core.annotation.OperatorLog;
import com.orion.ops.framework.common.utils.Valid;
import com.orion.ops.framework.web.core.annotation.RestWrapper;
import com.orion.ops.module.asset.define.operator.ExecOperatorType;
import com.orion.ops.module.asset.entity.request.exec.ExecCommandRequest;
@@ -47,15 +48,26 @@ public class ExecController {
return execService.execCommand(request);
}
@OperatorLog(ExecOperatorType.INTERRUPT_COMMAND)
@PostMapping("/interrupt-command")
@OperatorLog(ExecOperatorType.INTERRUPT_EXEC)
@PostMapping("/interrupt")
@Operation(summary = "中断执行命令")
@PreAuthorize("@ss.hasPermission('asset:exec:interrupt-command')")
public HttpWrapper<?> interruptCommand(@RequestBody ExecInterruptRequest request) {
execService.interruptCommand(request);
@PreAuthorize("@ss.hasPermission('asset:exec:interrupt-exec')")
public HttpWrapper<?> interruptExec(@RequestBody ExecInterruptRequest request) {
Long logId = Valid.notNull(request.getLogId());
execService.interruptExec(logId);
return HttpWrapper.ok();
}
// log
@OperatorLog(ExecOperatorType.INTERRUPT_HOST)
@PostMapping("/interrupt-host")
@Operation(summary = "中断执行命令")
@PreAuthorize("@ss.hasPermission('asset:exec:interrupt-exec')")
public HttpWrapper<?> interruptHostExec(@RequestBody ExecInterruptRequest request) {
Long hostLogId = Valid.notNull(request.getHostLogId());
execService.interruptHostExec(hostLogId);
return HttpWrapper.ok();
}
// TODO tail log
}

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.controller;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.ops.framework.biz.operator.log.core.annotation.OperatorLog;
import com.orion.ops.framework.common.validator.group.Batch;
import com.orion.ops.framework.common.validator.group.Page;
import com.orion.ops.framework.log.core.annotation.IgnoreLog;
import com.orion.ops.framework.log.core.enums.IgnoreLogMode;
@@ -9,7 +10,9 @@ import com.orion.ops.framework.web.core.annotation.RestWrapper;
import com.orion.ops.module.asset.define.operator.ExecOperatorType;
import com.orion.ops.module.asset.entity.request.exec.ExecLogQueryRequest;
import com.orion.ops.module.asset.entity.vo.ExecHostLogVO;
import com.orion.ops.module.asset.entity.vo.ExecLogStatusVO;
import com.orion.ops.module.asset.entity.vo.ExecLogVO;
import com.orion.ops.module.asset.enums.ExecSourceEnum;
import com.orion.ops.module.asset.service.ExecHostLogService;
import com.orion.ops.module.asset.service.ExecLogService;
import io.swagger.v3.oas.annotations.Operation;
@@ -59,6 +62,7 @@ public class ExecLogController {
@Operation(summary = "分页查询执行日志")
@PreAuthorize("@ss.hasPermission('asset:exec-log:query')")
public DataGrid<ExecLogVO> getExecLogPage(@Validated(Page.class) @RequestBody ExecLogQueryRequest request) {
request.setSource(ExecSourceEnum.BATCH.name());
return execLogService.getExecLogPage(request);
}
@@ -70,6 +74,14 @@ public class ExecLogController {
return execHostLogService.getExecHostLogList(logId);
}
@IgnoreLog(IgnoreLogMode.RET)
@GetMapping("/status")
@Operation(summary = "查询执行日志状态")
@PreAuthorize("@ss.hasPermission('asset:exec-log:query')")
public ExecLogStatusVO getExecLogStatus(@Validated(Batch.class) @RequestBody ExecLogQueryRequest request) {
return execLogService.getExecLogStatus(request.getIdList());
}
@OperatorLog(ExecOperatorType.DELETE_LOG)
@DeleteMapping("/delete")
@Operation(summary = "删除执行日志")
@@ -88,6 +100,7 @@ public class ExecLogController {
return execLogService.deleteExecLogByIdList(idList);
}
@OperatorLog(ExecOperatorType.DELETE_HOST_LOG)
@DeleteMapping("/delete-host")
@Operation(summary = "删除执行主机日志")
@Parameter(name = "id", description = "id", required = true)
@@ -96,5 +109,22 @@ public class ExecLogController {
return execHostLogService.deleteExecHostLogById(id);
}
@PostMapping("/query-count")
@Operation(summary = "查询执行日志数量")
@PreAuthorize("@ss.hasPermission('asset:exec-log:management:clear')")
public Long getExecLogCount(@RequestBody ExecLogQueryRequest request) {
request.setSource(ExecSourceEnum.BATCH.name());
return execLogService.queryExecLogCount(request);
}
@OperatorLog(ExecOperatorType.CLEAR_LOG)
@PostMapping("/clear")
@Operation(summary = "清空执行日志")
@PreAuthorize("@ss.hasPermission('asset:exec-log:management:clear')")
public Integer clearExecLog(@RequestBody ExecLogQueryRequest request) {
request.setSource(ExecSourceEnum.BATCH.name());
return execLogService.clearExecLog(request);
}
}

View File

@@ -19,7 +19,11 @@ public class ExecOperatorType extends InitializingOperatorTypes {
public static final String EXEC_COMMAND = "exec:exec-command";
public static final String INTERRUPT_COMMAND = "exec:interrupt-command";
public static final String INTERRUPT_EXEC = "exec:interrupt-exec";
public static final String INTERRUPT_HOST = "exec:interrupt-host";
public static final String DELETE_HOST_LOG = "exec:delete-host-log";
public static final String DELETE_LOG = "exec:delete-log";
@@ -29,7 +33,9 @@ public class ExecOperatorType extends InitializingOperatorTypes {
public OperatorType[] types() {
return new OperatorType[]{
new OperatorType(M, EXEC_COMMAND, "执行主机命令"),
new OperatorType(M, INTERRUPT_COMMAND, "中断执行命令"),
new OperatorType(M, INTERRUPT_EXEC, "中断执行命令"),
new OperatorType(M, INTERRUPT_HOST, "中断主机执行命令 ${logId} ${hostName}"),
new OperatorType(H, DELETE_HOST_LOG, "删除主机执行日志 ${logId} ${hostName}"),
new OperatorType(H, DELETE_LOG, "删除执行日志 ${count} 条"),
new OperatorType(H, CLEAR_LOG, "清理执行日志 ${count} 条"),
};

View File

@@ -2,11 +2,14 @@ package com.orion.ops.module.asset.entity.request.exec;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.orion.ops.framework.common.entity.PageRequest;
import com.orion.ops.framework.common.validator.group.Batch;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.List;
/**
* 批量执行日志 查询请求对象
@@ -26,6 +29,10 @@ public class ExecLogQueryRequest extends PageRequest {
@Schema(description = "id")
private Long id;
@NotEmpty(groups = Batch.class)
@Schema(description = "id")
private List<Long> idList;
@Schema(description = "执行用户id")
private Long userId;

View File

@@ -0,0 +1,34 @@
package com.orion.ops.module.asset.entity.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.List;
/**
* 批量执行日志状态 视图响应对象
*
* @author Jiahang Li
* @version 1.0.1
* @since 2024-3-11 11:31
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(name = "ExecLogStatusVO", description = "批量执行日志状态 视图响应对象")
public class ExecLogStatusVO implements Serializable {
private static final long serialVersionUID = 1L;
@Schema(description = "执行状态列表")
private List<ExecLogVO> logList;
@Schema(description = "主机状态列表")
private List<ExecHostLogVO> hostList;
}

View File

@@ -1,5 +1,12 @@
package com.orion.ops.module.asset.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 批量执行主机状态
*
@@ -7,35 +14,44 @@ package com.orion.ops.module.asset.enums;
* @version 1.0.0
* @since 2024/3/11 17:08
*/
@Getter
@AllArgsConstructor
public enum ExecHostStatusEnum {
/**
* 等待中
*/
WAITING,
WAITING(true),
/**
* 执行中
*/
RUNNING,
RUNNING(true),
/**
* 执行完成
*/
COMPLETED,
COMPLETED(false),
/**
* 执行失败
*/
FAILED,
FAILED(false),
/**
* 中断执行
*/
INTERRUPTED,
INTERRUPTED(false),
;
private final boolean closeable;
public static final List<String> CLOSEABLE_STATUS = Arrays.stream(ExecHostStatusEnum.values())
.filter(ExecHostStatusEnum::isCloseable)
.map(Enum::name)
.collect(Collectors.toList());
public static ExecHostStatusEnum of(String status) {
if (status == null) {
return null;

View File

@@ -1,5 +1,8 @@
package com.orion.ops.module.asset.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 批量执行状态
*
@@ -7,30 +10,34 @@ package com.orion.ops.module.asset.enums;
* @version 1.0.0
* @since 2024/3/11 17:08
*/
@Getter
@AllArgsConstructor
public enum ExecStatusEnum {
/**
* 等待中
*/
WAITING,
WAITING(true),
/**
* 执行中
*/
RUNNING,
RUNNING(true),
/**
* 执行完成
*/
COMPLETED,
COMPLETED(false),
/**
* 执行失败
*/
FAILED,
FAILED(false),
;
private final boolean closeable;
public static ExecStatusEnum of(String status) {
if (status == null) {
return null;

View File

@@ -15,6 +15,7 @@ import com.orion.ops.module.asset.enums.ExecHostStatusEnum;
import com.orion.ops.module.asset.handler.host.exec.dto.ExecCommandHostDTO;
import com.orion.ops.module.asset.service.HostTerminalService;
import com.orion.spring.SpringHolder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@@ -39,10 +40,13 @@ public class ExecCommandHandler implements IExecCommandHandler {
private final ExecHostLogDAO execHostLogDAO = SpringHolder.getBean(ExecHostLogDAO.class);
private final ExecCommandHostDTO command;
private final ExecCommandHostDTO execHostCommand;
private final TimeoutChecker timeoutChecker;
@Getter
private ExecHostStatusEnum status;
private SessionStore sessionStore;
private CommandExecutor executor;
@@ -53,39 +57,44 @@ public class ExecCommandHandler implements IExecCommandHandler {
private volatile boolean interrupted;
public ExecCommandHandler(ExecCommandHostDTO command, TimeoutChecker timeoutChecker) {
this.command = command;
public ExecCommandHandler(ExecCommandHostDTO execHostCommand, TimeoutChecker timeoutChecker) {
this.status = ExecHostStatusEnum.WAITING;
this.execHostCommand = execHostCommand;
this.timeoutChecker = timeoutChecker;
}
@Override
public void run() {
Long id = command.getHostLogId();
log.info("ExecCommandHandler run start id: {}, info: {}", id, JSON.toJSONString(command));
Long id = execHostCommand.getHostLogId();
Exception ex = null;
log.info("ExecCommandHandler run start id: {}, info: {}", id, JSON.toJSONString(execHostCommand));
// 更新状态
this.updateStatus(ExecHostStatusEnum.RUNNING, null);
try {
// 更新状态
this.updateStatus(ExecHostStatusEnum.RUNNING, null);
// 执行命令
this.execCommand();
if (executor.isTimeout()) {
// 更新状态
this.updateStatus(ExecHostStatusEnum.FAILED, new TimeoutException());
} else {
// 更新状态
this.updateStatus(ExecHostStatusEnum.COMPLETED, null);
}
log.info("ExecCommandHandler run complete id: {}", id);
} catch (Exception e) {
log.error("ExecCommandHandler run error id: {}", id, e);
// TODO
if (this.interrupted) {
this.updateStatus(ExecHostStatusEnum.INTERRUPTED, null);
} else {
this.updateStatus(ExecHostStatusEnum.FAILED, e);
}
ex = e;
} finally {
Streams.close(this);
}
// 执行回调
if (this.interrupted) {
// TODO 测试
// 中断执行
this.updateStatus(ExecHostStatusEnum.INTERRUPTED, null);
} else if (ex != null) {
// 执行失败
this.updateStatus(ExecHostStatusEnum.FAILED, ex);
} else if (executor.isTimeout()) {
// 更新执行超时
this.updateStatus(ExecHostStatusEnum.FAILED, new TimeoutException());
} else {
// 更新执行完成
this.updateStatus(ExecHostStatusEnum.COMPLETED, null);
}
}
/**
@@ -95,13 +104,12 @@ public class ExecCommandHandler implements IExecCommandHandler {
*/
private void execCommand() throws Exception {
// 打开日志流
this.logOutputStream = fileClient.getContentOutputStream(command.getLogPath());
this.logOutputStream = fileClient.getContentOutputStream(execHostCommand.getLogPath());
// 打开会话
this.sessionStore = hostTerminalService.openSessionStore(command.getHostId());
this.executor = sessionStore.getCommandExecutor(Strings.replaceCRLF(command.getCommand()));
// TODO 超时
this.sessionStore = hostTerminalService.openSessionStore(execHostCommand.getHostId());
this.executor = sessionStore.getCommandExecutor(Strings.replaceCRLF(execHostCommand.getCommand()));
// 执行命令
executor.timeout(command.getTimeout(), TimeUnit.SECONDS, timeoutChecker);
executor.timeout(execHostCommand.getTimeout(), TimeUnit.SECONDS, timeoutChecker);
executor.merge();
executor.transfer(logOutputStream);
executor.connect();
@@ -115,9 +123,10 @@ public class ExecCommandHandler implements IExecCommandHandler {
* @param ex ex
*/
private void updateStatus(ExecHostStatusEnum status, Exception ex) {
Long id = command.getHostLogId();
this.status = status;
Long id = execHostCommand.getHostLogId();
String statusName = status.name();
log.info("ExecCommandHandler.updateStatus id: {}, status: {}", id, statusName);
log.info("ExecCommandHandler.updateStatus start id: {}, status: {}", id, statusName);
ExecHostLogDO update = new ExecHostLogDO();
update.setId(id);
update.setStatus(statusName);
@@ -136,7 +145,8 @@ public class ExecCommandHandler implements IExecCommandHandler {
// 中断
update.setFinishTime(new Date());
}
execHostLogDAO.updateById(update);
int effect = execHostLogDAO.updateById(update);
log.info("ExecCommandHandler.updateStatus finish id: {}, effect: {}", id, effect);
}
@Override
@@ -146,6 +156,8 @@ public class ExecCommandHandler implements IExecCommandHandler {
@Override
public void interrupted() {
log.info("ExecCommandHandler.interrupted id: {}, interrupted: {}, closed: {}",
execHostCommand.getHostLogId(), interrupted, closed);
if (this.interrupted || this.closed) {
return;
}
@@ -154,6 +166,20 @@ public class ExecCommandHandler implements IExecCommandHandler {
this.close();
}
@Override
public void close() {
log.info("ExecCommandHandler.closed id: {}, closed: {}",
execHostCommand.getHostLogId(), closed);
if (this.closed) {
return;
}
this.closed = true;
Streams.close(executor);
Streams.close(sessionStore);
Streams.close(logOutputStream);
// TODO 关闭日志
}
/**
* 获取错误信息
*
@@ -175,15 +201,8 @@ public class ExecCommandHandler implements IExecCommandHandler {
}
@Override
public void close() {
if (this.closed) {
return;
}
this.closed = true;
Streams.close(executor);
Streams.close(sessionStore);
Streams.close(logOutputStream);
// TODO 关闭日志
public Long getHostId() {
return execHostCommand.getHostId();
}
}

View File

@@ -11,7 +11,9 @@ import com.orion.ops.module.asset.entity.domain.ExecLogDO;
import com.orion.ops.module.asset.enums.ExecStatusEnum;
import com.orion.ops.module.asset.handler.host.exec.dto.ExecCommandDTO;
import com.orion.ops.module.asset.handler.host.exec.dto.ExecCommandHostDTO;
import com.orion.ops.module.asset.handler.host.exec.manager.ExecManager;
import com.orion.spring.SpringHolder;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import java.util.Date;
@@ -30,29 +32,31 @@ public class ExecTaskHandler implements IExecTaskHandler {
private static final ExecLogDAO execLogDAO = SpringHolder.getBean(ExecLogDAO.class);
private final ExecCommandDTO command;
private static final ExecManager execManager = SpringHolder.getBean(ExecManager.class);
private final ExecCommandDTO execCommand;
private TimeoutChecker timeoutChecker;
private List<ExecCommandHandler> handlers;
@Getter
private List<IExecCommandHandler> handlers;
public ExecTaskHandler(ExecCommandDTO command) {
this.command = command;
public ExecTaskHandler(ExecCommandDTO execCommand) {
this.execCommand = execCommand;
this.handlers = Lists.newList();
}
// TODO manager
@Override
public void run() {
Long id = command.getLogId();
Long id = execCommand.getLogId();
// 添加任务
execManager.addTask(id, this);
log.info("ExecTaskHandler.run start id: {}", id);
// 更新状态
this.updateStatus(ExecStatusEnum.RUNNING);
try {
// TODO 添加
// 更新状态
this.updateStatus(ExecStatusEnum.RUNNING);
// 执行命令
this.runHostCommand(command.getHosts());
this.runHostCommand(execCommand.getHosts());
// 更新状态-执行完成
log.info("ExecTaskHandler.run completed id: {}", id);
this.updateStatus(ExecStatusEnum.COMPLETED);
@@ -60,12 +64,20 @@ public class ExecTaskHandler implements IExecTaskHandler {
// 更新状态-执行失败
this.updateStatus(ExecStatusEnum.FAILED);
log.error("ExecTaskHandler.run error id: {}", id, e);
// TODO 移除
} finally {
this.close();
// 释放资源
Streams.close(this);
// 移除任务
execManager.removeTask(id);
}
}
@Override
public void interrupted() {
log.info("ExecTaskHandler-interrupted id: {}", execCommand.getLogId());
handlers.forEach(IExecCommandHandler::interrupted);
}
/**
* 执行主机命令
*
@@ -74,7 +86,7 @@ public class ExecTaskHandler implements IExecTaskHandler {
*/
private void runHostCommand(List<ExecCommandHostDTO> hosts) throws Exception {
// 超时检查
if (command.getTimeout() != 0) {
if (execCommand.getTimeout() != 0) {
this.timeoutChecker = TimeoutChecker.create(Const.MS_S_1);
AssetThreadPools.TIMEOUT_CHECK.execute(this.timeoutChecker);
}
@@ -90,11 +102,15 @@ public class ExecTaskHandler implements IExecTaskHandler {
}
}
private Integer updateStatus(ExecStatusEnum status) {
Long id = command.getLogId();
/**
* 更新状态
*
* @param status status
*/
private void updateStatus(ExecStatusEnum status) {
Long id = execCommand.getLogId();
String statusName = status.name();
log.info("ExecTaskHandler-updateStatus id: {}, status: {}", id, statusName);
log.info("ExecTaskHandler-updateStatus start id: {}, status: {}", id, statusName);
ExecLogDO update = new ExecLogDO();
update.setId(id);
update.setStatus(statusName);
@@ -108,13 +124,16 @@ public class ExecTaskHandler implements IExecTaskHandler {
// 执行失败
update.setFinishTime(new Date());
}
return execLogDAO.updateById(update);
int effect = execLogDAO.updateById(update);
log.info("ExecTaskHandler-updateStatus finish id: {}, effect: {}", id, effect);
}
@Override
public void close() {
log.info("ExecTaskHandler-close id: {}", execCommand.getLogId());
Streams.close(timeoutChecker);
this.handlers.forEach(Streams::close);
// TODO 关闭日志
}
}

View File

@@ -1,6 +1,7 @@
package com.orion.ops.module.asset.handler.host.exec.handler;
import com.orion.lang.able.SafeCloseable;
import com.orion.ops.module.asset.enums.ExecHostStatusEnum;
/**
* 命令执行器定义
@@ -23,4 +24,18 @@ public interface IExecCommandHandler extends Runnable, SafeCloseable {
*/
void interrupted();
/**
* 获取当前状态
*
* @return status
*/
ExecHostStatusEnum getStatus();
/**
* 获取主机 id
*
* @return hostId
*/
Long getHostId();
}

View File

@@ -2,6 +2,8 @@ package com.orion.ops.module.asset.handler.host.exec.handler;
import com.orion.lang.able.SafeCloseable;
import java.util.List;
/**
* 执行任务处理器
*
@@ -11,4 +13,16 @@ import com.orion.lang.able.SafeCloseable;
*/
public interface IExecTaskHandler extends Runnable, SafeCloseable {
/**
* 获取主机执行器
*
* @return handlers
*/
List<IExecCommandHandler> getHandlers();
/**
* 中断执行
*/
void interrupted();
}

View File

@@ -0,0 +1,49 @@
package com.orion.ops.module.asset.handler.host.exec.manager;
import com.orion.ops.module.asset.handler.host.exec.handler.IExecTaskHandler;
import org.springframework.stereotype.Component;
import java.util.concurrent.ConcurrentHashMap;
/**
* 执行管理器
*
* @author Jiahang Li
* @version 1.0.0
* @since 2024/3/13 11:20
*/
@Component
public class ExecManager {
private final ConcurrentHashMap<Long, IExecTaskHandler> execTasks = new ConcurrentHashMap<>();
/**
* 添加任务
*
* @param id id
* @param task task
*/
public void addTask(Long id, IExecTaskHandler task) {
execTasks.put(id, task);
}
/**
* 获取任务
*
* @param id id
* @return task
*/
public IExecTaskHandler getTask(Long id) {
return execTasks.get(id);
}
/**
* 移除任务
*
* @param id id
*/
public void removeTask(Long id) {
execTasks.remove(id);
}
}

View File

@@ -135,6 +135,7 @@ public class TransferHandler implements ITransferHandler {
@Override
public void close() {
log.info("TransferHandler.close channelId: {}", channel.getId());
sessions.values().forEach(Streams::close);
}

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.service;
import com.orion.lang.define.wrapper.DataGrid;
import com.orion.ops.module.asset.entity.request.exec.ExecLogQueryRequest;
import com.orion.ops.module.asset.entity.vo.ExecLogStatusVO;
import com.orion.ops.module.asset.entity.vo.ExecLogVO;
import java.util.List;
@@ -31,6 +32,14 @@ public interface ExecLogService {
*/
DataGrid<ExecLogVO> getExecLogPage(ExecLogQueryRequest request);
/**
* 获取执行日志状态
*
* @param idList idList
* @return status
*/
ExecLogStatusVO getExecLogStatus(List<Long> idList);
/**
* 查询批量执行日志数量
*

View File

@@ -1,7 +1,6 @@
package com.orion.ops.module.asset.service;
import com.orion.ops.module.asset.entity.request.exec.ExecCommandRequest;
import com.orion.ops.module.asset.entity.request.exec.ExecInterruptRequest;
import com.orion.ops.module.asset.entity.vo.ExecVO;
/**
@@ -24,8 +23,15 @@ public interface ExecService {
/**
* 中断命令执行
*
* @param request request
* @param logId logId
*/
void interruptCommand(ExecInterruptRequest request);
void interruptExec(Long logId);
/**
* 中断命令执行
*
* @param hostLogId hostLogId
*/
void interruptHostExec(Long hostLogId);
}

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.utils.collect.Lists;
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.utils.Valid;
import com.orion.ops.module.asset.convert.ExecHostLogConvert;
@@ -67,6 +68,9 @@ public class ExecHostLogServiceImpl implements ExecHostLogService {
// 删除
int effect = execHostLogDAO.deleteById(id);
log.info("ExecHostLogService-deleteExecHostLogById id: {}, effect: {}", id, effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.LOG_ID, record.getLogId());
OperatorLogs.add(OperatorLogs.HOST_NAME, record.getHostName());
return effect;
}

View File

@@ -4,18 +4,25 @@ 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.Arrays1;
import com.orion.lang.utils.collect.Lists;
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.utils.Valid;
import com.orion.ops.module.asset.convert.ExecHostLogConvert;
import com.orion.ops.module.asset.convert.ExecLogConvert;
import com.orion.ops.module.asset.dao.ExecHostLogDAO;
import com.orion.ops.module.asset.dao.ExecLogDAO;
import com.orion.ops.module.asset.entity.domain.ExecHostLogDO;
import com.orion.ops.module.asset.entity.domain.ExecLogDO;
import com.orion.ops.module.asset.entity.domain.HostConnectLogDO;
import com.orion.ops.module.asset.entity.request.exec.ExecLogQueryRequest;
import com.orion.ops.module.asset.entity.vo.ExecHostLogVO;
import com.orion.ops.module.asset.entity.vo.ExecLogStatusVO;
import com.orion.ops.module.asset.entity.vo.ExecLogVO;
import com.orion.ops.module.asset.service.ExecHostLogService;
import com.orion.ops.module.asset.service.ExecLogService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.List;
@@ -35,6 +42,12 @@ public class ExecLogServiceImpl implements ExecLogService {
@Resource
private ExecLogDAO execLogDAO;
@Resource
private ExecHostLogDAO execHostLogDAO;
@Resource
private ExecHostLogService execHostLogService;
@Override
public ExecLogVO getExecLogById(Long id) {
// 查询
@@ -54,32 +67,71 @@ public class ExecLogServiceImpl implements ExecLogService {
.dataGrid(ExecLogConvert.MAPPER::to);
}
@Override
public ExecLogStatusVO getExecLogStatus(List<Long> idList) {
// 查询执行状态
List<ExecLogVO> logList = execLogDAO.of()
.createWrapper()
.select(ExecLogDO::getId, ExecLogDO::getStatus, ExecLogDO::getFinishTime)
.in(ExecLogDO::getId, idList)
.then()
.list(ExecLogConvert.MAPPER::to);
// 查询主机状态
List<ExecHostLogVO> hostList = execHostLogDAO.of()
.createWrapper()
.select(ExecHostLogDO::getId,
ExecHostLogDO::getStatus,
ExecHostLogDO::getFinishTime,
ExecHostLogDO::getExitStatus,
ExecHostLogDO::getErrorMessage)
.in(ExecHostLogDO::getLogId, idList)
.then()
.list(ExecHostLogConvert.MAPPER::to);
// 返回
return ExecLogStatusVO.builder()
.logList(logList)
.hostList(hostList)
.build();
}
@Override
public Long queryExecLogCount(ExecLogQueryRequest request) {
return execLogDAO.selectCount(this.buildQueryWrapper(request));
}
@Override
@Transactional(rollbackFor = Exception.class)
public Integer deleteExecLogById(Long id) {
log.info("ExecLogService-deleteExecLogById id: {}", id);
// 检查数据是否存在
ExecLogDO record = execLogDAO.selectById(id);
Valid.notNull(record, ErrorMessage.DATA_ABSENT);
// 删除
// 删除执行日志
int effect = execLogDAO.deleteById(id);
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(Lists.singleton(id));
log.info("ExecLogService-deleteExecLogById id: {}, effect: {}", id, effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
return effect;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Integer deleteExecLogByIdList(List<Long> idList) {
log.info("ExecLogService-deleteExecLogByIdList idList: {}", idList);
// 删除执行日志
int effect = execLogDAO.deleteBatchIds(idList);
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(idList);
log.info("ExecLogService-deleteExecLogByIdList effect: {}", effect);
// 设置日志参数
OperatorLogs.add(OperatorLogs.COUNT, effect);
return effect;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Integer clearExecLog(ExecLogQueryRequest request) {
log.info("ExecLogService.clearExecLog start {}", JSON.toJSONString(request));
// 查询
@@ -91,10 +143,10 @@ public class ExecLogServiceImpl implements ExecLogService {
.collect(Collectors.toList());
int effect = 0;
if (!idList.isEmpty()) {
// 删除
// 删除执行日志
effect = execLogDAO.delete(wrapper);
// TODO
// 删除主机日志
execHostLogService.deleteExecHostLogByLogId(idList);
}
log.info("ExecLogService.clearExecLog finish {}", effect);
// 设置日志参数

View File

@@ -2,6 +2,7 @@ package com.orion.ops.module.asset.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.orion.lang.id.UUIds;
import com.orion.lang.utils.Strings;
import com.orion.lang.utils.collect.Maps;
@@ -23,7 +24,6 @@ import com.orion.ops.module.asset.entity.domain.ExecHostLogDO;
import com.orion.ops.module.asset.entity.domain.ExecLogDO;
import com.orion.ops.module.asset.entity.domain.HostDO;
import com.orion.ops.module.asset.entity.request.exec.ExecCommandRequest;
import com.orion.ops.module.asset.entity.request.exec.ExecInterruptRequest;
import com.orion.ops.module.asset.entity.vo.ExecVO;
import com.orion.ops.module.asset.enums.ExecHostStatusEnum;
import com.orion.ops.module.asset.enums.ExecSourceEnum;
@@ -32,6 +32,9 @@ import com.orion.ops.module.asset.enums.HostConfigTypeEnum;
import com.orion.ops.module.asset.handler.host.exec.ExecTaskExecutors;
import com.orion.ops.module.asset.handler.host.exec.dto.ExecCommandDTO;
import com.orion.ops.module.asset.handler.host.exec.dto.ExecCommandHostDTO;
import com.orion.ops.module.asset.handler.host.exec.handler.IExecCommandHandler;
import com.orion.ops.module.asset.handler.host.exec.handler.IExecTaskHandler;
import com.orion.ops.module.asset.handler.host.exec.manager.ExecManager;
import com.orion.ops.module.asset.service.AssetAuthorizedDataService;
import com.orion.ops.module.asset.service.ExecService;
import lombok.extern.slf4j.Slf4j;
@@ -74,6 +77,9 @@ public class ExecServiceImpl implements ExecService {
@Resource
private AssetAuthorizedDataService assetAuthorizedDataService;
@Resource
private ExecManager execManager;
@Override
@Transactional(rollbackFor = Exception.class)
public ExecVO execCommand(ExecCommandRequest request) {
@@ -85,6 +91,7 @@ public class ExecServiceImpl implements ExecService {
// 检查主机权限
List<Long> authorizedHostIdList = assetAuthorizedDataService.getUserAuthorizedHostId(userId, HostConfigTypeEnum.SSH);
hostIdList.removeIf(s -> !authorizedHostIdList.contains(s));
log.info("ExecService.startExecCommand host hostList: {}", hostIdList);
Valid.notEmpty(hostIdList, ErrorMessage.CHECK_AUTHORIZED_HOST);
List<HostDO> hosts = hostDAO.selectBatchIds(hostIdList);
// 插入日志
@@ -100,7 +107,7 @@ public class ExecServiceImpl implements ExecService {
execLogDAO.insert(execLog);
Long execId = execLog.getId();
// 获取内置参数
Map<String, Object> builtinsParams = getBaseBuiltinsParams(user, execId, request.getParameter());
Map<String, Object> builtinsParams = this.getBaseBuiltinsParams(user, execId, request.getParameter());
// 设置主机日志
List<ExecHostLogDO> execHostLogs = hosts.stream()
.map(s -> {
@@ -143,8 +150,99 @@ public class ExecServiceImpl implements ExecService {
}
@Override
public void interruptCommand(ExecInterruptRequest request) {
@Transactional(rollbackFor = Exception.class)
public void interruptExec(Long logId) {
log.info("ExecService.interruptExec start logId: {}", logId);
// 获取执行记录
ExecLogDO execLog = execLogDAO.selectById(logId);
Valid.notNull(execLog, ErrorMessage.DATA_ABSENT);
// 检查状态
if (!ExecStatusEnum.of(execLog.getStatus()).isCloseable()) {
return;
}
// 中断执行
IExecTaskHandler task = execManager.getTask(logId);
if (task != null) {
log.info("ExecService.interruptExec interrupted logId: {}", logId);
// 中断
task.interrupted();
} else {
log.info("ExecService.interruptExec updateStatus start logId: {}", logId);
// 不存在则直接修改状态
ExecLogDO updateExec = new ExecLogDO();
updateExec.setId(logId);
updateExec.setStatus(ExecStatusEnum.COMPLETED.name());
updateExec.setFinishTime(new Date());
int effect = execLogDAO.updateById(updateExec);
// 更新主机状态
ExecHostLogDO updateHost = new ExecHostLogDO();
updateHost.setStatus(ExecHostStatusEnum.INTERRUPTED.name());
updateHost.setFinishTime(new Date());
LambdaQueryWrapper<ExecHostLogDO> updateHostWrapper = execHostLogDAO.lambda()
.eq(ExecHostLogDO::getLogId, logId)
.in(ExecHostLogDO::getStatus, ExecHostStatusEnum.CLOSEABLE_STATUS);
effect += execHostLogDAO.update(updateHost, updateHostWrapper);
log.info("ExecService.interruptExec updateStatus finish logId: {}, effect: {}", logId, effect);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void interruptHostExec(Long hostLogId) {
log.info("ExecService.interruptHostExec start hostLogId: {}", hostLogId);
// 获取执行记录
ExecHostLogDO hostLog = execHostLogDAO.selectById(hostLogId);
Valid.notNull(hostLog, ErrorMessage.DATA_ABSENT);
Long logId = hostLog.getLogId();
// 添加日志参数
OperatorLogs.add(OperatorLogs.LOG_ID, logId);
OperatorLogs.add(OperatorLogs.HOST_NAME, hostLog.getHostName());
// 检查状态
if (!ExecHostStatusEnum.of(hostLog.getStatus()).isCloseable()) {
return;
}
// 中断执行
IExecTaskHandler task = execManager.getTask(logId);
if (task != null) {
log.info("ExecService.interruptHostExec interrupted logId: {}, hostLogId: {}", logId, hostLogId);
IExecCommandHandler handler = task.getHandlers()
.stream()
.filter(s -> s.getHostId().equals(hostLog.getHostId()))
.findFirst()
.orElse(null);
// 中断
if (handler != null) {
handler.interrupted();
}
} else {
log.info("ExecService.interruptHostExec updateStatus start logId: {}, hostLogId: {}", logId, hostLogId);
// 不存在则直接修改状态
ExecHostLogDO updateHost = new ExecHostLogDO();
updateHost.setId(hostLogId);
updateHost.setStatus(ExecHostStatusEnum.INTERRUPTED.name());
updateHost.setFinishTime(new Date());
int effect = execHostLogDAO.updateById(updateHost);
// 查询执行状态
ExecLogDO execLog = execLogDAO.selectById(logId);
if (ExecStatusEnum.of(execLog.getStatus()).isCloseable()) {
// 状态可修改则需要检查其他主机任务是否已经完成
Long closeableCount = execHostLogDAO.of()
.createWrapper()
.eq(ExecHostLogDO::getLogId, logId)
.in(ExecHostLogDO::getStatus, ExecHostStatusEnum.CLOSEABLE_STATUS)
.then()
.count();
if (closeableCount == 0) {
// 修改任务状态
ExecLogDO updateExec = new ExecLogDO();
updateExec.setId(logId);
updateExec.setStatus(ExecStatusEnum.COMPLETED.name());
updateExec.setFinishTime(new Date());
effect += execLogDAO.updateById(updateExec);
}
}
log.info("ExecService.interruptHostExec updateStatus finish logId: {}, hostLogId: {}, effect: {}", logId, hostLogId, effect);
}
}
/**

View File

@@ -54,12 +54,9 @@ public class HostSftpLogServiceImpl implements HostSftpLogService {
return vo;
}).collect(Collectors.toList());
// 返回
DataGrid<HostSftpLogVO> result = new DataGrid<>();
result.setRows(rows);
DataGrid<HostSftpLogVO> result = new DataGrid<>(rows, dataGrid.getTotal());
result.setPage(dataGrid.getPage());
result.setLimit(dataGrid.getLimit());
result.setSize(dataGrid.getSize());
result.setTotal(dataGrid.getTotal());
return result;
}

View File

@@ -59,6 +59,7 @@ public class OperatorLogController {
@PostMapping("/query-count")
@Operation(summary = "查询操作日志数量")
@PreAuthorize("@ss.hasPermission('infra:operator-log:clear')")
public Long getOperatorLogCount(@RequestBody OperatorLogQueryRequest request) {
return operatorLogService.getOperatorLogCount(request);
}