OCT REM: 1. 更新中间件管理接口

This commit is contained in:
HuangXin 2025-04-09 18:53:12 +08:00
parent 69cb8c6e92
commit 0e3189689b
7 changed files with 158 additions and 183 deletions

View File

@ -5,12 +5,14 @@ import com.cmcc.magent.annotation.EncryptionProtocol;
import com.cmcc.magent.annotation.OperationLogAnnotation;
import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.common.MiddlewareManagerCommand;
import com.cmcc.magent.common.MiddlewareType;
import com.cmcc.magent.common.MulReturnType;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.pojo.dto.DeployMiddlewareFileReq;
import com.cmcc.magent.pojo.dto.DeploymentMiddlewareReq;
import com.cmcc.magent.pojo.dto.ProtocolReq;
import com.cmcc.magent.pojo.po.BaseRespStatus;
import com.cmcc.magent.pojo.po.DeploymentContext;
import com.cmcc.magent.pojo.po.RemoteFileDetails;
import com.cmcc.magent.pojo.vo.DeploymentMiddlewareResp;
import com.cmcc.magent.pojo.vo.DeploymentTaskStatusResp;
@ -20,7 +22,9 @@ import com.cmcc.magent.validation.group.ValidGroups;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.constraints.UUID;
import org.springframework.context.annotation.Profile;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@ -29,8 +33,10 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
/**
* MiddlewareManagerApi 类提供了中间件管理的 RESTful API 接口
@ -44,114 +50,113 @@ import java.util.Map;
@Tag(name = "中间件管理接口")
@RequestMapping(value = "/api/middleware")
@Slf4j
@Validated
public class MiddlewareManagerApi {
@Resource
private MiddlewareManagerService middlewareManagerService;
private Map<MiddlewareManagerCommand, RemoteFileDetails> createCommandFilesMap(DeployMiddlewareFileReq req) {
Map<MiddlewareManagerCommand, RemoteFileDetails> command = new java.util.HashMap<>(10);
if (req.getDeploymentCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT, RemoteFileDetails.builder()
.url(req.getDeploymentCmd().getUrl())
.fileName(req.getDeploymentCmd().getFileName())
.checksum(req.getDeploymentCmd().getChecksum())
.build());
}
if (req.getConfigCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_CONFIG, RemoteFileDetails.builder()
.url(req.getConfigCmd().getUrl())
.fileName(req.getConfigCmd().getFileName())
.checksum(req.getConfigCmd().getChecksum())
.build());
}
if (req.getStartCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_START, RemoteFileDetails.builder()
.url(req.getStartCmd().getUrl())
.fileName(req.getStartCmd().getFileName())
.checksum(req.getStartCmd().getChecksum())
.build());
}
if (req.getStopCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_STOP, RemoteFileDetails.builder()
.url(req.getStopCmd().getUrl())
.fileName(req.getStopCmd().getFileName())
.checksum(req.getStopCmd().getChecksum())
.build());
}
if (req.getRestartCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_RESTART, RemoteFileDetails.builder()
.url(req.getRestartCmd().getUrl())
.fileName(req.getRestartCmd().getFileName())
.checksum(req.getRestartCmd().getChecksum())
.build());
}
if (req.getUninstallCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_UNINSTALL, RemoteFileDetails.builder()
.url(req.getUninstallCmd().getUrl())
.fileName(req.getUninstallCmd().getFileName())
.checksum(req.getUninstallCmd().getChecksum())
.build());
}
if (req.getStatusCmd() != null) {
command.put(MiddlewareManagerCommand.COMMAND_STATUS, RemoteFileDetails.builder()
.url(req.getStatusCmd().getUrl())
.fileName(req.getStatusCmd().getFileName())
.checksum(req.getStatusCmd().getChecksum())
.build());
}
return command;
}
/**
* 根据部署中间件请求创建命令映射
*
* @param req 部署中间件请求
* @return 命令映射
*/
private Map<MiddlewareManagerCommand, String> createCommandMap(DeploymentMiddlewareReq req) {
Map<MiddlewareManagerCommand, String> command = new java.util.HashMap<>(10);
if (HelperUtils.stringNotEmptyOrNull(req.getDeploymentCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT, req.getDeploymentCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getConfigCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_CONFIG, req.getConfigCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getStartCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_START, req.getStartCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getStopCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_STOP, req.getStopCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getRestartCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_RESTART, req.getRestartCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getUninstallCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_UNINSTALL, req.getUninstallCmd());
}
if (HelperUtils.stringNotEmptyOrNull(req.getStatusCmd())) {
command.put(MiddlewareManagerCommand.COMMAND_STATUS, req.getStatusCmd());
}
private Map<MiddlewareManagerCommand, Object> createCommandMap(DeploymentMiddlewareReq req) {
Map<MiddlewareManagerCommand, Object> command = new HashMap<>(10);
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_DEPLOYMENT, req.getDeploymentCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_CONFIG, req.getConfigCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_START, req.getStartCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_STOP, req.getStopCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_RESTART, req.getRestartCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_UNINSTALL, req.getUninstallCmd());
addCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_STATUS, req.getStatusCmd());
return command;
}
/**
* 根据部署中间件文件请求创建命令映射
*
* @param req 部署中间件文件请求
* @return 命令映射
*/
private Map<MiddlewareManagerCommand, Object> createCommandFilesMap(DeployMiddlewareFileReq req) {
Map<MiddlewareManagerCommand, Object> command = new HashMap<>(10);
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_DEPLOYMENT, req.getDeploymentCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_CONFIG, req.getConfigCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_START, req.getStartCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_STOP, req.getStopCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_RESTART, req.getRestartCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_UNINSTALL, req.getUninstallCmd());
addFileCommandIfPresent(command, MiddlewareManagerCommand.COMMAND_STATUS, req.getStatusCmd());
return command;
}
private void addCommandIfPresent(Map<MiddlewareManagerCommand, Object> command, MiddlewareManagerCommand key, String value) {
if (HelperUtils.stringNotEmptyOrNull(value)) {
command.put(key, value);
}
}
private void addFileCommandIfPresent(Map<MiddlewareManagerCommand, Object> command, MiddlewareManagerCommand key,
RemoteFileDetails fileCmd) {
if (fileCmd != null) {
command.put(key,
RemoteFileDetails.builder()
.url(fileCmd.getUrl())
.fileName(fileCmd.getFileName())
.checksum(fileCmd.getChecksum())
.build());
}
}
/**
* 处理部署请求的通用逻辑
*
* @param mr 协议请求
* @param commandMapCreator 命令映射创建函数
* @return 协议响应
*/
private <T> ProtocolResp<? extends BaseRespStatus> processDeploymentRequest(ProtocolReq<T> mr,
Function<T, Map<MiddlewareManagerCommand, Object>> commandMapCreator) {
List<String> validate = HelperUtils.validate(mr,
ValidGroups.ProtocolCommonValid.class,
ValidGroups.MiddlewareDeploymentReqValid.class);
if (!validate.isEmpty()) {
return ProtocolResp.result(ErrorCode.ERR_PARAMEXCEPTION,
ErrorCode.ERR_PARAMEXCEPTION.getHttpCode(),
HelperUtils.formatErrorMessage(ErrorCode.ERR_PARAMEXCEPTION, validate));
}
T req = mr.getMsgContent();
DeploymentContext context;
if (req instanceof DeploymentMiddlewareReq v) {
context = DeploymentContext.builder()
.middlewareType(MiddlewareType.getEnumByString(v.getMiddleware()))
.middlewareVersion(v.getMiddlewareVer())
.commands(commandMapCreator.apply(req))
.configFiles(v.getConfigFiles())
.build();
} else if (req instanceof DeployMiddlewareFileReq v) {
context = DeploymentContext.builder()
.middlewareType(MiddlewareType.getEnumByString(v.getMiddleware()))
.middlewareVersion(v.getMiddlewareVer())
.commands(commandMapCreator.apply(req))
.configFiles(v.getConfigFiles())
.build();
} else {
throw new IllegalArgumentException("Unsupported request type");
}
MulReturnType<ErrorCode, String> ret = middlewareManagerService.executeDeployment(context);
return ret.getFirstParam() == ErrorCode.ERR_OK ? ProtocolResp.result(DeploymentMiddlewareResp.builder()
.deploymentId(ret.getSecondParam())
.build()) : ProtocolResp.result(
ErrorCode.ERR_CALLDEVICE,
ret.getFirstParam().getHttpCode(),
HelperUtils.formatErrorMessage(ret.getFirstParam(), Collections.singletonList(ret.getSecondParam())));
}
/**
* 中间件部署
*
@ -166,31 +171,7 @@ public class MiddlewareManagerApi {
OperationType = "SYSLOG_TYPE_CREATE",
OperationDesc = "SYSLOG_MOD_MIDDLEWAREAPI")
public ProtocolResp<? extends BaseRespStatus> deploymentMiddleware(@RequestBody ProtocolReq<DeploymentMiddlewareReq> mr) {
List<String> validate = HelperUtils.validate(mr,
ValidGroups.ProtocolCommonValid.class,
ValidGroups.MiddlewareDeploymentReqValid.class);
// 如果校验通过validate为空否则validate包含未校验通过项
if (validate.isEmpty()) {
DeploymentMiddlewareReq req = mr.getMsgContent();
MulReturnType<ErrorCode, String> ret = middlewareManagerService.executeCommandTask(req.getMiddleware(),
req.getMiddlewareVer(),
createCommandMap(req),
req.getConfigFiles());
if (ret.getFirstParam() == ErrorCode.ERR_OK) {
return ProtocolResp.result(DeploymentMiddlewareResp.builder().deploymentId(ret.getSecondParam()).build());
} else {
return ProtocolResp.result(ErrorCode.ERR_CALLDEVICE,
ret.getFirstParam().getHttpCode(),
HelperUtils.formatErrorMessage(ret.getFirstParam(),
Collections.singletonList(ret.getSecondParam())));
}
} else {
return ProtocolResp.result(ErrorCode.ERR_PARAMEXCEPTION,
ErrorCode.ERR_PARAMEXCEPTION.getHttpCode(),
HelperUtils.formatErrorMessage(ErrorCode.ERR_PARAMEXCEPTION, validate));
}
return processDeploymentRequest(mr, this::createCommandMap);
}
/**
@ -207,31 +188,7 @@ public class MiddlewareManagerApi {
OperationDesc = "SYSLOG_MOD_MIDDLEWAREAPI")
@Profile({"host", "vm"})
public ProtocolResp<? extends BaseRespStatus> deploymentMiddlewareFiles(@RequestBody ProtocolReq<DeployMiddlewareFileReq> mr) {
List<String> validate = HelperUtils.validate(mr,
ValidGroups.ProtocolCommonValid.class,
ValidGroups.MiddlewareDeploymentReqValid.class);
// 如果校验通过validate为空否则validate包含未校验通过项
if (validate.isEmpty()) {
DeployMiddlewareFileReq req = mr.getMsgContent();
MulReturnType<ErrorCode, String> ret = middlewareManagerService.executeTask(req.getMiddleware(),
req.getMiddlewareVer(),
createCommandFilesMap(req),
req.getConfigFiles());
if (ret.getFirstParam() == ErrorCode.ERR_OK) {
return ProtocolResp.result(DeploymentMiddlewareResp.builder().deploymentId(ret.getSecondParam()).build());
} else {
return ProtocolResp.result(ErrorCode.ERR_CALLDEVICE,
ret.getFirstParam().getHttpCode(),
HelperUtils.formatErrorMessage(ret.getFirstParam(),
Collections.singletonList(ret.getSecondParam())));
}
} else {
return ProtocolResp.result(ErrorCode.ERR_PARAMEXCEPTION,
ErrorCode.ERR_PARAMEXCEPTION.getHttpCode(),
HelperUtils.formatErrorMessage(ErrorCode.ERR_PARAMEXCEPTION, validate));
}
return processDeploymentRequest(mr, this::createCommandFilesMap);
}
/**
@ -246,15 +203,7 @@ public class MiddlewareManagerApi {
@OperationLogAnnotation(OperationModule = "SYSLOG_MOD_MODDLEWAREAPI",
OperationType = "SYSLOG_TYPE_READ",
OperationDesc = "SYSLOG_MOD_MIDDLEWAREAPI")
public ProtocolResp<? extends BaseRespStatus> getDeploymentMiddlewareResult(@RequestParam String deploymentTaskId) {
final int maxUuidLen = 32;
if (deploymentTaskId == null || deploymentTaskId.isBlank() || deploymentTaskId.length() < maxUuidLen) {
return ProtocolResp.result(ErrorCode.ERR_PARAMEXCEPTION,
ErrorCode.ERR_PARAMEXCEPTION.getHttpCode(),
new String[] {ErrorCode.ERR_PARAMEXCEPTION.getDescription()});
}
public ProtocolResp<? extends BaseRespStatus> getDeploymentMiddlewareResult(@RequestParam @UUID String deploymentTaskId) {
var deploymentTaskStatus = middlewareManagerService.getDeploymentTaskStatus(deploymentTaskId);
return ProtocolResp.result(DeploymentTaskStatusResp.builder()

View File

@ -10,6 +10,7 @@ import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
@ -45,11 +46,11 @@ public class ControllerExceptionHandler {
* @return 包含错误信息的 ProtocolResp 对象
*/
@ExceptionHandler({NoHandlerFoundException.class, ServletException.class, NullPointerException.class, SQLException.class,
CommonErrorCodeException.class, SecurityProtocolException.class})
CommonErrorCodeException.class, SecurityProtocolException.class, ConstraintViolationException.class,
MethodArgumentNotValidException.class})
@ResponseBody
public ProtocolResp<BaseRespStatus> handleException(HttpServletResponse rsp, HttpServletRequest req, Exception ex) {
String reqType = "";
try {
reqType = req.getMethod();
String reqPath = req.getRequestURI();
@ -97,6 +98,12 @@ public class ControllerExceptionHandler {
.stream()
.map(v -> idx.getAndIncrement() + ": " + v.getDefaultMessage())
.toList());
} else if (ex instanceof ConstraintViolationException e) {
AtomicInteger idx = new AtomicInteger();
errMsg.addAll(e.getConstraintViolations()
.stream()
.map(v -> idx.getAndIncrement() + ": {" + v.getInvalidValue() + "} " + v.getMessage())
.toList());
} else {
errMsg.add(ex.getMessage());
}

View File

@ -3,6 +3,7 @@ package com.cmcc.magent.service;
import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.common.MiddlewareManagerCommand;
import com.cmcc.magent.common.MulReturnType;
import com.cmcc.magent.pojo.po.DeploymentContext;
import com.cmcc.magent.pojo.po.DeploymentTaskStatus;
import com.cmcc.magent.pojo.po.RemoteFileDetails;
@ -18,35 +19,17 @@ import java.util.Map;
* @since 2025-02-17
*/
public interface MiddlewareManagerService {
/**
* 执行命令任务
*
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令映射,其中键为 {@link MiddlewareManagerCommand} 枚举类型,表示要执行的命令类型;
* 值为 {@link String} 类型,表示该命令对应的实际命令字符串
* @param configFiles 配置文件列表
* @param context {@link DeploymentContext} 中间件部署参数
* @return 返回执行结果, 包含错误码和执行输出
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
MulReturnType<ErrorCode, String> executeCommandTask(String middleware, String ver, Map<MiddlewareManagerCommand, String> command,
List<RemoteFileDetails> configFiles);
MulReturnType<ErrorCode, String> executeDeployment(DeploymentContext context);
/**
* 执行任务
*
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令与远程文件详情的映射,其中键为 {@link MiddlewareManagerCommand} 枚举类型,表示要执行的命令类型;
* 值为 {@link RemoteFileDetails} 类型,表示该命令对应的远程文件详情
* @param configFiles 相关配置文件列表
* @return 返回一个 MulReturnType 对象其中包含命令执行的状态码和相关信息
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
MulReturnType<ErrorCode, String> executeTask(String middleware, String ver, Map<MiddlewareManagerCommand, RemoteFileDetails> command,
List<RemoteFileDetails> configFiles);
/**
* 打印指定流状态机的信息包括其所有子流程的活动信息

View File

@ -21,6 +21,7 @@ import com.cmcc.magent.misc.SpringBootBeanUtils;
import com.cmcc.magent.pojo.entry.MiddlewareData;
import com.cmcc.magent.pojo.entry.WorkflowData;
import com.cmcc.magent.pojo.po.DeploymentContentDetails;
import com.cmcc.magent.pojo.po.DeploymentContext;
import com.cmcc.magent.pojo.po.DeploymentOutput;
import com.cmcc.magent.pojo.po.DeploymentTaskStatus;
import com.cmcc.magent.pojo.po.LocalShellContext;
@ -349,6 +350,31 @@ public class HostAgentManagerServiceImpl implements HostAgentManagerService, Wor
return context;
}
@Override
public MulReturnType<ErrorCode, String> executeDeployment(DeploymentContext context) {
return Optional.ofNullable(context.getCommands()).map(commands -> {
if (commands.values().stream().allMatch(RemoteFileDetails.class::isInstance)) {
Map<MiddlewareManagerCommand, RemoteFileDetails> remoteFileCommands = castCommands(commands, RemoteFileDetails.class);
return executeTask(context.getMiddlewareType().name(),
context.getMiddlewareVersion(),
remoteFileCommands,
context.getConfigFiles());
} else if (commands.values().stream().allMatch(String.class::isInstance)) {
Map<MiddlewareManagerCommand, String> stringCommands = castCommands(commands, String.class);
return executeCommandTask(context.getMiddlewareType().name(),
context.getMiddlewareVersion(),
stringCommands,
context.getConfigFiles());
} else {
return new MulReturnType<>(ErrorCode.ERR_NOSUCHTYPE, "Parameter type error");
}
}).orElse(new MulReturnType<>(ErrorCode.ERR_PARAMEXCEPTION, "Command parameter error"));
}
private <T> Map<MiddlewareManagerCommand, T> castCommands(Map<MiddlewareManagerCommand, ?> commands, Class<T> clazz) {
return commands.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, entry -> clazz.cast(entry.getValue())));
}
/**
* 执行命令任务
*
@ -360,8 +386,7 @@ public class HostAgentManagerServiceImpl implements HostAgentManagerService, Wor
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
@Override
public MulReturnType<ErrorCode, String> executeCommandTask(String middleware, String ver, Map<MiddlewareManagerCommand, String> command,
private MulReturnType<ErrorCode, String> executeCommandTask(String middleware, String ver, Map<MiddlewareManagerCommand, String> command,
List<RemoteFileDetails> configFiles) {
String uuid = UUID.randomUUID().toString();
MiddlewareData data = new MiddlewareData();
@ -424,8 +449,7 @@ public class HostAgentManagerServiceImpl implements HostAgentManagerService, Wor
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
@Override
public MulReturnType<ErrorCode, String> executeTask(String middleware, String ver,
private MulReturnType<ErrorCode, String> executeTask(String middleware, String ver,
Map<MiddlewareManagerCommand, RemoteFileDetails> command,
List<RemoteFileDetails> configFiles) {
String uuid = UUID.randomUUID().toString();

View File

@ -18,4 +18,10 @@ COMMAND_START=setup command
COMMAND_STOP=Stop command
COMMAND_RESTART=Restart command
COMMAND_UNINSTALL=Uninstall command
COMMAND_STATUS=Get status command
COMMAND_STATUS=Get status command
MIDDLEWARE_REDIS=Redis Middleware
MIDDLEWARE_ZEDIS=Zedis Middleware
MIDDLEWARE_NGINX=Nginx Middleware
MIDDLEWARE_ZGINX=Zginx Middleware
MIDDLEWARE_KEEPALIVED=KeepAlived Middleware
MIDDLEWARE_CUSTOM=Custom Middleware

View File

@ -1,4 +1,5 @@
NORMAL=\u6B63\u5E38
MIDDLEWARE_REDIS=Redis ???
LOCKED=\u5DF2\u9501\u5B9A
DISABLED=\u5DF2\u7981\u7528
DELETED=\u5DF2\u5220\u9664
@ -18,4 +19,9 @@ COMMAND_START=????
COMMAND_STOP=????
COMMAND_RESTART=????
COMMAND_UNINSTALL=????
COMMAND_STATUS=??????
COMMAND_STATUS=??????
MIDDLEWARE_ZEDIS=Zedis ???
MIDDLEWARE_NGINX=Ngind ???
MIDDLEWARE_ZGINX=Zginx ???
MIDDLEWARE_KEEPALIVED=KeepAlived ???
MIDDLEWARE_CUSTOM=??????