OCT REM: 1. 中间件管理接口支持服务器发送OSS部署脚本下载

This commit is contained in:
HuangXin 2025-02-25 16:40:08 +08:00
parent 925b11bede
commit 454c099448
8 changed files with 631 additions and 59 deletions

View File

@ -38,15 +38,10 @@ public enum MiddlewareManagerCommand implements BaseEnum {
*/
COMMAND_RESTART(4, "重启命令"),
/**
* 重新配置命令
*/
COMMAND_RECONFIG(5, "重新配置命令"),
/**
* 卸载命令
*/
COMMAND_UNINSTALL(6, "卸载命令");
COMMAND_UNINSTALL(5, "卸载命令");
private final int code;
private final String readme;

View File

@ -7,9 +7,11 @@ import com.cmcc.magent.common.ErrorCode;
import com.cmcc.magent.common.MiddlewareManagerCommand;
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.RemoteFileDetails;
import com.cmcc.magent.pojo.vo.DeploymentMiddlewareResp;
import com.cmcc.magent.pojo.vo.ProtocolResp;
import com.cmcc.magent.service.MiddlewareManagerService;
@ -22,8 +24,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* MiddlewareManagerApi 类提供了中间件管理的 RESTful API 接口
@ -41,6 +46,66 @@ 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());
}
return command.entrySet().stream().sorted(Comparator.comparingInt(entry -> entry.getKey().getValue())).collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue,
LinkedHashMap::new));
}
/**
* 根据部署中间件请求创建命令映射
*
@ -74,11 +139,15 @@ public class MiddlewareManagerApi {
command.put(MiddlewareManagerCommand.COMMAND_UNINSTALL, req.getUninstallCmd());
}
return command;
return command.entrySet().stream().sorted(Comparator.comparingInt(entry -> entry.getKey().getValue())).collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue,
LinkedHashMap::new));
}
/**
* 部署中间件的 API 接口
* 中间件部署
*
* @param mr 包含部署中间件请求的协议请求
* @return 部署中间件的协议响应
@ -116,4 +185,44 @@ public class MiddlewareManagerApi {
HelperUtils.formatErrorMessage(ErrorCode.ERR_PARAMEXCEPTION, validate));
}
}
/**
* 中间件部署V2
*
* @param mr 包含部署中间件请求的协议请求
* @return 部署中间件的协议响应
*/
@PostMapping("/v2/deployment")
@EncryptionProtocol
@DecryptionProtocol
@OperationLogAnnotation(OperationModule = "SYSLOG_MOD_MODDLEWAREAPI",
OperationType = "SYSLOG_TYPE_CREATE",
OperationDesc = "SYSLOG_MOD_MIDDLEWAREAPI")
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));
}
}
}

View File

@ -0,0 +1,80 @@
package com.cmcc.magent.pojo.dto;
import com.cmcc.magent.pojo.po.RemoteFileDetails;
import com.cmcc.magent.validation.group.ValidGroups;
import com.cmcc.magent.validation.valids.ValidFixValues;
import com.fasterxml.jackson.annotation.JsonInclude;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* 部署中间件请求的数据传输对象
* <p>
* 此类用于封装中间件部署请求的相关信息包括中间件类型版本和配置文件等
* </p>
*
* @author huangxin@cmhi.chinamobile.com
* @version 1.0.0
* @since 2025-02-25
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonInclude(JsonInclude.Include.NON_NULL)
public class DeployMiddlewareFileReq {
/**
* 中间件类型不能为空并且必须是指定的固定值之一Redis, Nginx, Keepalived
*/
@NotBlank(message = "middleware Not Blank", groups = {ValidGroups.MiddlewareDeploymentReqValid.class})
@ValidFixValues(value = {"Redis", "Nginx", "Keepalived"}, ignoreSwitchCase = true, groups = {ValidGroups.MiddlewareDeploymentReqValid.class})
private String middleware;
/**
* 中间件版本信息
*/
private String middlewareVer;
/**
* 部署命令
*/
private RemoteFileDetails deploymentCmd;
/**
* 配置命令
*/
private RemoteFileDetails configCmd;
/**
* 启动命令
*/
private RemoteFileDetails startCmd;
/**
* 停止命令
*/
private RemoteFileDetails stopCmd;
/**
* 重启命令
*/
private RemoteFileDetails restartCmd;
/**
* 卸载命令
*/
private RemoteFileDetails uninstallCmd;
/**
* 配置文件列表不能为空
*/
@NotEmpty(message = "middleware Not Empty", groups = {ValidGroups.MiddlewareDeploymentReqValid.class})
private List<RemoteFileDetails> configFiles;
}

View File

@ -1,8 +1,13 @@
package com.cmcc.magent.pojo.po;
import com.cmcc.magent.validation.group.ValidGroups;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 文件下载配置类
@ -12,17 +17,22 @@ import lombok.Data;
* @since 2025-02-18
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Schema(description = "远程文件信息类包含配置文件的URL和校验和")
public class RemoteFileDetails {
/**
* 配置文件URL
*/
@NotBlank(message = "url Not Blank", groups = {ValidGroups.MiddlewareDeploymentReqValid.class})
public String url;
/**
* 配置文件名
*/
@NotBlank(message = "fileName Not Blank", groups = {ValidGroups.MiddlewareDeploymentReqValid.class})
public String fileName;
/**

View File

@ -1,9 +1,9 @@
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.RemoteFileDetails;
import com.cmcc.magent.common.MiddlewareManagerCommand;
import java.util.List;
import java.util.Map;
@ -21,13 +21,31 @@ public interface MiddlewareManagerService {
/**
* 执行命令任务
*
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令参数映射
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令映射,其中键为 {@link MiddlewareManagerCommand} 枚举类型,表示要执行的命令类型;
* 值为 {@link String} 类型,表示该命令对应的实际命令字符串
* @param configFiles 配置文件列表
* @return 返回执行结果,包含错误码和执行输出
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
MulReturnType<ErrorCode, String> executeCommandTask(String middleware, String ver, Map<MiddlewareManagerCommand, String> command,
List<RemoteFileDetails> configFiles);
/**
* 执行任务
*
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令与远程文件详情的映射,其中键为 {@link MiddlewareManagerCommand} 枚举类型,表示要执行的命令类型;
* 值为 {@link RemoteFileDetails} 类型,表示该命令对应的远程文件详情
* @param configFiles 相关配置文件列表
* @return 返回一个 MulReturnType 对象其中包含命令执行的状态码和相关信息
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
MulReturnType<ErrorCode, String> executeCommandTask(String middleware, String ver, Map<MiddlewareManagerCommand, String> command, List<RemoteFileDetails> configFiles);
MulReturnType<ErrorCode, String> executeTask(String middleware, String ver,
Map<MiddlewareManagerCommand, RemoteFileDetails> command,
List<RemoteFileDetails> configFiles);
}

View File

@ -10,9 +10,11 @@ import com.cmcc.magent.crypto.arithmetic.CryptoHelper;
import com.cmcc.magent.mapper.MiddlewareDataMapper;
import com.cmcc.magent.misc.ExecutingCommand;
import com.cmcc.magent.misc.HelperUtils;
import com.cmcc.magent.misc.JsonUtils;
import com.cmcc.magent.pojo.entry.MiddlewareData;
import com.cmcc.magent.pojo.po.RemoteFileDetails;
import com.cmcc.magent.service.MiddlewareManagerService;
import com.fasterxml.jackson.core.JsonProcessingException;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@ -24,11 +26,13 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
/**
* MiddlewareManagerServiceImpl 类实现了 MiddlewareManagerService 接口
@ -67,8 +71,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
private String getFilenameForCommand(MiddlewareManagerCommand cmd) {
return switch (cmd) {
case COMMAND_DEPLOYMENT -> DEPLOYMENT_FILENAME;
case COMMAND_RECONFIG,
COMMAND_CONFIG -> CONFIG_FILENAME;
case COMMAND_CONFIG -> CONFIG_FILENAME;
case COMMAND_START -> START_FILENAME;
case COMMAND_STOP -> STOP_FILENAME;
case COMMAND_RESTART -> RESTART_FILENAME;
@ -103,18 +106,18 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
* 创建工作目录
*
* @param workDir 工作目录路径
* @return 如果创建成功, 返回 true;否则返回 false
* @return 如果创建成功, 返回 {@link ErrorCode#ERR_OK};否则返回 {@link ErrorCode#ERR_SYSTEMEXCEPTION}
*/
private boolean createWorkDirectory(String workDir) {
private ErrorCode createWorkDirectory(String workDir) {
Path path = Paths.get(workDir);
if (!Files.exists(path)) {
try {
Files.createDirectories(path);
} catch (Exception e) {
return false;
return ErrorCode.ERR_SYSTEMEXCEPTION;
}
}
return true;
return ErrorCode.ERR_OK;
}
/**
@ -129,7 +132,6 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
case COMMAND_DEPLOYMENT:
data.setDeployment(param);
break;
case COMMAND_RECONFIG:
case COMMAND_CONFIG:
data.setConfig(param);
break;
@ -151,6 +153,44 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
});
}
/**
* 处理命令参数,并更新 MiddlewareData 对象
*
* @param data 要更新的 MiddlewareData 对象
* @param command 命令参数映射
*/
private void processFilesCommands(MiddlewareData data, Map<MiddlewareManagerCommand, RemoteFileDetails> command) {
command.forEach((cmd, param) -> {
try {
String fieldString = JsonUtils.getJson(param);
switch (cmd) {
case COMMAND_DEPLOYMENT:
data.setDeployment(fieldString);
break;
case COMMAND_CONFIG:
data.setConfig(fieldString);
break;
case COMMAND_START:
data.setStart(fieldString);
break;
case COMMAND_STOP:
data.setStop(fieldString);
break;
case COMMAND_RESTART:
data.setRestart(fieldString);
break;
case COMMAND_UNINSTALL:
data.setUninstall(fieldString);
break;
default:
break;
}
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
}
/**
* 保存命令到 Shell 脚本文件
*
@ -179,12 +219,13 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
* @param configFiles 配置文件列表
* @return 返回一个 MulReturnType 对象,其中包含下载和校验结果的错误码和相关信息
*/
private MulReturnType<ErrorCode, String> downloadAndValidateConfigFiles(String workDir, List<RemoteFileDetails> configFiles) {
private MulReturnType<ErrorCode, String> downloadAndValidateFiles(String workDir, List<RemoteFileDetails> configFiles) {
for (RemoteFileDetails file : configFiles) {
try {
String saveName = Paths.get(workDir + File.separator + file.getFileName()).toString();
OssService service = ossFactory.getOssService();
String saveName = Paths.get(workDir + File.separator + file.getFileName()).toString();
// FileDownloader dl = new FileDownloader(file.getUrl(), saveName);
// dl.downloadFile();
OssService service = ossFactory.getOssService();
service.download(new URL(file.getUrl()), new File(saveName));
if (HelperUtils.stringNotEmptyOrNull(file.getChecksum())) {
@ -209,9 +250,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
* @param command 命令参数映射
*/
private void runCommand(String workDir, Map<MiddlewareManagerCommand, String> command) {
TreeMap<MiddlewareManagerCommand, String> sorted = new TreeMap<>(command);
for (MiddlewareManagerCommand cmd : sorted.keySet()) {
for (MiddlewareManagerCommand cmd : command.keySet()) {
String filename = getFilenameForCommand(cmd);
List<String> ret = ExecutingCommand.runNative("/bin/bash", workDir + File.separator + filename);
log.info("Run {} Command: {}", cmd.getEnumString(), ret);
@ -249,7 +288,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
String workDir = Paths.get(commonConfigure.getDataRootDirectory() + "/" + data.getUid()).toString();
if (!createWorkDirectory(workDir)) {
if (createWorkDirectory(workDir) != ErrorCode.ERR_OK) {
return new MulReturnType<>(ErrorCode.ERR_SYSTEMEXCEPTION, "");
}
@ -260,7 +299,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
return err;
}
err = downloadAndValidateConfigFiles(workDir, configFiles);
err = downloadAndValidateFiles(workDir, configFiles);
if (err.getFirstParam() != ErrorCode.ERR_OK) {
return err;
}
@ -275,7 +314,7 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
return;
}
error = downloadAndValidateConfigFiles(workDir, configFiles);
error = downloadAndValidateFiles(workDir, configFiles);
if (error.getFirstParam() != ErrorCode.ERR_OK) {
log.error("---- Finish Task {} Because Of Download Config File Error: {}", data.getUid(), error.getSecondParam());
return;
@ -287,4 +326,81 @@ public class MiddlewareManagerServiceImpl implements MiddlewareManagerService {
return new MulReturnType<>(ErrorCode.ERR_OK, data.getUid());
}
/**
* 执行任务
*
* @param middleware 中间件名称
* @param ver 中间件版本
* @param command 命令与远程文件详情的映射,其中键为 {@link MiddlewareManagerCommand} 枚举类型,表示要执行的命令类型;
* 值为 {@link RemoteFileDetails} 类型,表示该命令对应的远程文件详情
* @param configFiles 相关配置文件列表
* @return 返回一个 MulReturnType 对象其中包含命令执行的状态码和相关信息
* 第一个参数为 ErrorCode 类型表示执行结果的错误码
* 第二个参数为 String 类型表示执行结果的详细信息
*/
@Override
public MulReturnType<ErrorCode, String> executeTask(String middleware, String ver,
Map<MiddlewareManagerCommand, RemoteFileDetails> command,
List<RemoteFileDetails> configFiles) {
MulReturnType<ErrorCode, String> err;
MiddlewareData data = new MiddlewareData();
data.setMiddleware(middleware);
data.setMiddlewareVer(ver);
data.setWorkDirectory(commonConfigure.getDataRootDirectory());
processFilesCommands(data, command);
int nRow = middlewareDataMapper.insert(data);
if (nRow != 1) {
return new MulReturnType<>(ErrorCode.ERR_DATABASE, data.getUid());
}
String workDir = Paths.get(commonConfigure.getDataRootDirectory() + "/" + data.getUid()).toString();
if (createWorkDirectory(workDir) != ErrorCode.ERR_OK) {
return new MulReturnType<>(ErrorCode.ERR_SYSTEMEXCEPTION, "");
}
// 创建一个新的 LinkedHashMap 来保持顺序
Map<MiddlewareManagerCommand, String> cmd = command.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey,
entry -> entry.getValue().getUrl(),
(oldValue, newValue) -> oldValue,
LinkedHashMap::new));
if (!commonConfigure.isAsyncDeployment()) {
err = downloadAndValidateFiles(workDir, new ArrayList<>(command.values()));
if (err.getFirstParam() != ErrorCode.ERR_OK) {
return err;
}
err = downloadAndValidateFiles(workDir, configFiles);
if (err.getFirstParam() != ErrorCode.ERR_OK) {
return err;
}
runCommand(workDir, cmd);
} else {
CompletableFuture.runAsync(() -> {
log.info("++++ Task {} Start Running...", data.getUid());
MulReturnType<ErrorCode, String> error = downloadAndValidateFiles(workDir, new ArrayList<>(command.values()));
if (error.getFirstParam() != ErrorCode.ERR_OK) {
log.error("---- Finish Task {} Because Of Save Command Error: {}", data.getUid(), error.getSecondParam());
return;
}
error = downloadAndValidateFiles(workDir, configFiles);
if (error.getFirstParam() != ErrorCode.ERR_OK) {
log.error("---- Finish Task {} Because Of Download Config File Error: {}", data.getUid(), error.getSecondParam());
return;
}
runCommand(workDir, cmd);
log.info("---- Task {} Finished", data.getUid());
});
}
return new MulReturnType<>(ErrorCode.ERR_OK, data.getUid());
}
}

View File

@ -66,6 +66,24 @@ public class MiddlewareManagerApiTest {
"deploymentCmd":"echo deploymentCmd","configCmd":"echo configCmd","startCmd":"echo startCmd",\
"stopCmd":"echo stopCmd","restartCmd":"echo restartCmd","uninstallCmd":"echo uninstallCmd"}}""";
private static final String fmtListScript = """
{"ver":1,"cryptoType":0,"timeStamp":%d,"msgContent":{"middleware":"Redis",\
"middlewareVer":"5:7.0.15","deploymentCmd":{"url":"http://test","fileName":"test.sh",\
"checksum":"test_md5"},"configCmd":{"url":"http://test","fileName":"test.sh","checksum":\
"test_md5"},"startCmd":{"url":"http://test","fileName":"test.sh","checksum":"test_md5"},\
"stopCmd":{"url":"http://test","fileName":"stop.sh","checksum":"test_md5"},"restartCmd":\
{"url":"http://test","fileName":"restart.sh","checksum":"test_md5"},"uninstallCmd":{"url":\
"http://test","fileName":"uninstall.sh","checksum":"test_md5"},"configFiles":[{"url":\
"http://test","fileName":"test.zip","checksum":"da496c0c7be34d53f193dd466364b10f"},{"url":\
"http://test","fileName":"test.zip","checksum":"test_md5"}]}}
""";
private static final String errFmtScript = """
{"ver":1,"cryptoType":0,"timeStamp":%d,"msgContent":{"middleware":"Redis",\
"middlewareVer":"5:7.0.15","deploymentCmd":{"url":"http://test","fileName":"test.sh",\
"checksum":"test_md5"}}}
""";
private MockedStatic<MessageUtil> mockMessageUtils;
private MockedStatic<HelperUtils> mockHelperUtils;
@ -112,9 +130,12 @@ public class MiddlewareManagerApiTest {
mockHelperUtils.when(() -> HelperUtils.validate(any(), any())).thenReturn(new ArrayList<>());
mockMessageUtils.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn("");
log.info("Result: {}", mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON)
.content(reqString)).andExpect(status().isOk()).andExpect(
jsonPath("$.msgContent.deploymentId").value("deploymentId")).andReturn().getResponse().getContentAsString());
log.info(mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.deploymentId").value("deploymentId"))
.andReturn()
.getResponse()
.getContentAsString());
}
/**
@ -141,16 +162,14 @@ public class MiddlewareManagerApiTest {
"0: " + ErrorCode.ERR_CALLDEVICE.getEnumString(), "1: " + err.getEnumString()});
log.info("Result: {}", mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON)
.content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(errReturn.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " +
errReturn.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " + err.getEnumString()))
.andReturn()
.getResponse()
.getContentAsString());
log.info("Ret: {}", mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(errReturn.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " + errReturn.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " + err.getEnumString()))
.andReturn()
.getResponse()
.getContentAsString());
}
/**
@ -175,15 +194,93 @@ public class MiddlewareManagerApiTest {
mockHelperUtils.when(() -> HelperUtils.formatErrorMessage(any(ErrorCode.class), any(List.class))).thenReturn(new String[] {
"0: " + err.getEnumString(), "1: " + validErr});
log.info("Result: {}", mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON)
.content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(err.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " +
err.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " + validErr))
.andReturn()
.getResponse()
.getContentAsString());
log.info(mockMvc.perform(post("/api/middleware/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(err.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " + err.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " +
validErr))
.andReturn()
.getResponse()
.getContentAsString());
}
@Test
@DisplayName("合法请求成功部署(V2)")
@SuppressWarnings("unchecked")
public void deploymentMiddlewareV2_ValidRequest_SuccessfulDeployment() throws Exception {
String reqString = String.format(fmtListScript, System.currentTimeMillis());
when(middlewareManagerService.executeTask(anyString(),
anyString(),
any(HashMap.class),
any(List.class))).thenReturn(new MulReturnType<>(ErrorCode.ERR_OK, "deploymentId"));
mockHelperUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
mockHelperUtils.when(() -> HelperUtils.validate(any(), any())).thenReturn(new ArrayList<>());
mockMessageUtils.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn("");
log.info(mockMvc.perform(post("/api/middleware/v2/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.deploymentId").value("deploymentId"))
.andReturn()
.getResponse()
.getContentAsString());
}
@Test
@DisplayName("合法请求服务错误(V2)")
@SuppressWarnings("unchecked")
public void deploymentMiddlewareV2_ValidRequest_ServiceError() throws Exception {
ErrorCode err = ErrorCode.ERR_SYSTEMEXCEPTION;
ErrorCode errReturn = ErrorCode.ERR_CALLDEVICE;
String reqString = String.format(fmtListScript, System.currentTimeMillis());
when(middlewareManagerService.executeTask(anyString(),
anyString(),
any(HashMap.class),
any(List.class))).thenReturn(new MulReturnType<>(err, err.getEnumString()));
mockMessageUtils.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn(err.getEnumString());
mockHelperUtils.when(() -> HelperUtils.validate(any(), any(Class[].class))).thenReturn(new ArrayList<>());
mockHelperUtils.when(() -> HelperUtils.formatErrorMessage(any(ErrorCode.class), any(List.class))).thenReturn(new String[] {
"0: " + ErrorCode.ERR_CALLDEVICE.getEnumString(), "1: " + err.getEnumString()});
log.info(mockMvc.perform(post("/api/middleware/v2/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(errReturn.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " + errReturn.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " + err.getEnumString()))
.andReturn()
.getResponse()
.getContentAsString());
}
@Test
@DisplayName("非法请求验证错误(V2)")
@SuppressWarnings("unchecked")
public void deploymentMiddlewareV2_InvalidRequest_ValidationErrors() throws Exception {
String validErr = "middleware Not Empty";
ErrorCode err = ErrorCode.ERR_PARAMEXCEPTION;
String reqString = String.format(errFmtScript, System.currentTimeMillis());
mockHelperUtils.when(() -> HelperUtils.validate(any(), any(Class[].class))).thenReturn(new ArrayList<>() {{
add(validErr);
}});
mockMessageUtils.when(() -> MessageUtil.get(anyString(), anyString())).thenReturn(err.getEnumString());
mockHelperUtils.when(() -> HelperUtils.validate(any(), any())).thenReturn(new ArrayList<>());
mockHelperUtils.when(() -> HelperUtils.formatErrorMessage(any(ErrorCode.class), any(List.class))).thenReturn(new String[] {
"0: " + err.getEnumString(), "1: " + validErr});
log.info(mockMvc.perform(post("/api/middleware/v2/deployment").contentType(MediaType.APPLICATION_JSON).content(reqString))
.andExpect(status().isOk())
.andExpect(jsonPath("$.msgContent.status").value(err.getCode()))
.andExpect(jsonPath("$.msgContent.message[0]").value("0: " + err.getEnumString()))
.andExpect(jsonPath("$.msgContent.message[1]").value("1: " + validErr))
.andReturn()
.getResponse()
.getContentAsString());
}
}

View File

@ -71,7 +71,7 @@ public class MiddlewareManagerServiceImplTest {
private OssFactory ossFactory;
@Mock
private OssService ossService;
private OssService service;
private static MockedStatic<HelperUtils> mockHelpUtils;
private static MockedStatic<CryptoHelper> mockCryptoHelper;
@ -151,7 +151,6 @@ public class MiddlewareManagerServiceImplTest {
command.put(MiddlewareManagerCommand.COMMAND_START, "echo start");
command.put(MiddlewareManagerCommand.COMMAND_STOP, "echo stop");
command.put(MiddlewareManagerCommand.COMMAND_RESTART, "echo restart");
command.put(MiddlewareManagerCommand.COMMAND_RECONFIG, "echo reconfig");
command.put(MiddlewareManagerCommand.COMMAND_UNINSTALL, "echo uninstall");
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeCommandTask("Redis", "6.0", command, new ArrayList<>());
@ -193,7 +192,6 @@ public class MiddlewareManagerServiceImplTest {
HashMap<MiddlewareManagerCommand, String> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
OssService service = mock(OssService.class);
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
@ -222,7 +220,6 @@ public class MiddlewareManagerServiceImplTest {
HashMap<MiddlewareManagerCommand, String> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
OssService service = mock(OssService.class);
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
@ -251,7 +248,6 @@ public class MiddlewareManagerServiceImplTest {
HashMap<MiddlewareManagerCommand, String> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
OssService service = mock(OssService.class);
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
@ -297,4 +293,155 @@ public class MiddlewareManagerServiceImplTest {
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeCommandTask("Redis", "6.0", command, new ArrayList<>());
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
}
@Test
@DisplayName("同步部署(部署脚本)")
public void executeTask_SyncDeployment_StartsSyncTask() throws IOException {
HashMap<MiddlewareManagerCommand, RemoteFileDetails> command = new HashMap<>();
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
when(commonConfigure.isAsyncDeployment()).thenReturn(false);
Path path = mock(Path.class);
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
when(Files.writeString(any(Path.class), anyString())).thenReturn(path);
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
mockCryptoHelper.when(() -> CryptoHelper.md5FileEncryption(anyString())).thenReturn("test_md5");
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT,
RemoteFileDetails.builder().url("http://test").fileName("deployment.sh").checksum("test_md5").build());
command.put(MiddlewareManagerCommand.COMMAND_CONFIG,
RemoteFileDetails.builder().url("http://test").fileName("config.sh").checksum("test_md5").build());
command.put(MiddlewareManagerCommand.COMMAND_START,
RemoteFileDetails.builder().url("http://test").fileName("start.sh").checksum("test_md5").build());
command.put(MiddlewareManagerCommand.COMMAND_STOP,
RemoteFileDetails.builder().url("http://test").fileName("stop.sh").checksum("test_md5").build());
command.put(MiddlewareManagerCommand.COMMAND_RESTART,
RemoteFileDetails.builder().url("http://test").fileName("restart.sh").checksum("test_md5").build());
command.put(MiddlewareManagerCommand.COMMAND_UNINSTALL,
RemoteFileDetails.builder().url("http://test").fileName("uninstall.sh").checksum("test_md5").build());
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", command, new ArrayList<>());
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
}
@Test
@DisplayName("工作目录创建失败(部署脚本)")
public void executeTask_WorkDirectoryCreationFails_ReturnsErrSystemException() {
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
mockFiles.when(() -> Files.createDirectories(any(Path.class))).thenThrow(new IOException());
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", new HashMap<>(), null);
assertEquals(ErrorCode.ERR_SYSTEMEXCEPTION, result.getFirstParam());
}
@Test
@DisplayName("数据库插入失败(部署脚本)")
public void executeTask_DatabaseInsertionFails_ReturnsErrDatabase() {
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(0);
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", new HashMap<>(), null);
assertEquals(ErrorCode.ERR_DATABASE, result.getFirstParam());
}
@Test
@DisplayName("下载部署脚本异常(部署脚本)")
public void executeSyncTask_downloadConfigFiles_ThrowException() {
RemoteFileDetails remoteFileDetails = new RemoteFileDetails();
HashMap<MiddlewareManagerCommand, RemoteFileDetails> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
when(commonConfigure.isAsyncDeployment()).thenReturn(false);
mockCryptoHelper.when(() -> CryptoHelper.md5FileEncryption(anyString())).thenThrow(new NoSuchAlgorithmException());
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT,
RemoteFileDetails.builder().url("http://test").fileName("").checksum("").build());
remoteFileDetails.setFileName("test");
remoteFileDetails.setUrl("http://test");
remoteFileDetails.setChecksum("test");
configFiles.add(remoteFileDetails);
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", command, configFiles);
assertEquals(ErrorCode.ERR_SYSTEMEXCEPTION, result.getFirstParam());
}
@Test
@DisplayName("下载配置文件校验失败(部署脚本)")
public void executeSyncTask_downloadConfigFiles_ChecksumError() {
RemoteFileDetails remoteFileDetails = new RemoteFileDetails();
HashMap<MiddlewareManagerCommand, RemoteFileDetails> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
when(commonConfigure.isAsyncDeployment()).thenReturn(false);
mockCryptoHelper.when(() -> CryptoHelper.md5FileEncryption(anyString())).thenReturn("demo");
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
mockExecutingCommand.when(() -> ExecutingCommand.runNative(anyString(), anyString())).thenReturn(new ArrayList<String>() {{
add("mock output");
}});
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT,
RemoteFileDetails.builder().url("http://test").fileName("deployment.sh").checksum("demo").build());
remoteFileDetails.setFileName("test");
remoteFileDetails.setUrl("http://test");
remoteFileDetails.setChecksum("test");
configFiles.add(remoteFileDetails);
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", command, configFiles);
assertEquals(ErrorCode.ERR_FILE_CHECKSUM, result.getFirstParam());
}
@Test
@DisplayName("异步部署(部署脚本)")
public void executeTask_AsyncDeployment_StartsAsyncTask() {
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
when(commonConfigure.isAsyncDeployment()).thenReturn(true);
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", new HashMap<>(), null);
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
}
@Test
@DisplayName("异步下载部署脚本异常(部署脚本)")
public void executeTaskAsync_downloadConfigFiles_ThrowException() {
RemoteFileDetails remoteFileDetails = new RemoteFileDetails();
HashMap<MiddlewareManagerCommand, RemoteFileDetails> command = new HashMap<>();
List<RemoteFileDetails> configFiles = new ArrayList<>();
when(ossFactory.getOssService()).thenReturn(service);
// 设置 download 方法的行为不进行真实调用直接返回
doNothing().when(service).download(any(URL.class), any(File.class));
when(middlewareDataMapper.insert(any(MiddlewareData.class))).thenReturn(1);
when(commonConfigure.isAsyncDeployment()).thenReturn(true);
mockCryptoHelper.when(() -> CryptoHelper.md5FileEncryption(anyString())).thenThrow(new NoSuchAlgorithmException());
mockHelpUtils.when(() -> HelperUtils.stringNotEmptyOrNull(anyString())).thenReturn(true);
command.put(MiddlewareManagerCommand.COMMAND_DEPLOYMENT,
RemoteFileDetails.builder().url("http://test").fileName("").checksum("").build());
remoteFileDetails.setFileName("test");
remoteFileDetails.setUrl("http://test");
remoteFileDetails.setChecksum("test");
configFiles.add(remoteFileDetails);
MulReturnType<ErrorCode, String> result = middlewareManagerService.executeTask("Redis", "6.0", command, configFiles);
assertEquals(ErrorCode.ERR_OK, result.getFirstParam());
}
}