初始化配置完善
This commit is contained in:
+18
-1
@@ -14,6 +14,7 @@ import com.cisd.tms.modules.device.support.HardwareStatusProbe;
|
|||||||
import com.cisd.tms.modules.device.support.SoftwareRuntimeProbe;
|
import com.cisd.tms.modules.device.support.SoftwareRuntimeProbe;
|
||||||
import com.cisd.tms.modules.device.support.SystemSoftwareVersionProbe;
|
import com.cisd.tms.modules.device.support.SystemSoftwareVersionProbe;
|
||||||
import com.cisd.tms.modules.device.support.UsageSnapshot;
|
import com.cisd.tms.modules.device.support.UsageSnapshot;
|
||||||
|
import com.cisd.tms.modules.init.dto.CurrentInitConfigResponse;
|
||||||
import com.cisd.tms.modules.init.service.InitService;
|
import com.cisd.tms.modules.init.service.InitService;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -177,10 +178,26 @@ public class DeviceRuntimeStatusServiceImpl implements DeviceRuntimeStatusServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
private BooleanSupplier receiverProbe() {
|
private BooleanSupplier receiverProbe() {
|
||||||
String productType = normalize(cisdPresetProperties.getProductType());
|
String productType = resolveReceiverProductType();
|
||||||
return "DIRECT".equals(productType) ? softwareRuntimeProbe::isDirectAppRunning : softwareRuntimeProbe::isStandardAppRunning;
|
return "DIRECT".equals(productType) ? softwareRuntimeProbe::isDirectAppRunning : softwareRuntimeProbe::isStandardAppRunning;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String resolveReceiverProductType() {
|
||||||
|
try {
|
||||||
|
String initState = normalize(initService.getDeviceInitStateSnapshot().initState());
|
||||||
|
if ("INITIALIZED".equals(initState)) {
|
||||||
|
CurrentInitConfigResponse current = initService.loadCurrentInitConfig();
|
||||||
|
String currentProductType = normalize(current == null ? null : current.getProductType());
|
||||||
|
if (!currentProductType.isBlank()) {
|
||||||
|
return currentProductType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (RuntimeException ignored) {
|
||||||
|
// Fallback to the preset product type when runtime init context is unavailable.
|
||||||
|
}
|
||||||
|
return normalize(cisdPresetProperties.getProductType());
|
||||||
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
private interface UsageSupplier {
|
private interface UsageSupplier {
|
||||||
UsageSnapshot get();
|
UsageSnapshot get();
|
||||||
|
|||||||
+91
-13
@@ -18,67 +18,128 @@ public class DefaultSoftwareRuntimeProbe implements SoftwareRuntimeProbe {
|
|||||||
private final Supplier<List<String>> processSnapshotLoader;
|
private final Supplier<List<String>> processSnapshotLoader;
|
||||||
private final Duration cacheTtl;
|
private final Duration cacheTtl;
|
||||||
private final LongSupplier nanoTimeSupplier;
|
private final LongSupplier nanoTimeSupplier;
|
||||||
|
private final CommandExitCodeSupplier commandExitCodeSupplier;
|
||||||
|
|
||||||
private final Object lock = new Object();
|
private final Object lock = new Object();
|
||||||
private volatile CachedProcessSnapshot cachedSnapshot;
|
private volatile CachedProcessSnapshot cachedSnapshot;
|
||||||
|
|
||||||
public DefaultSoftwareRuntimeProbe() {
|
public DefaultSoftwareRuntimeProbe() {
|
||||||
this(DefaultSoftwareRuntimeProbe::loadProcessSnapshot, DEFAULT_CACHE_TTL, System::nanoTime);
|
this(DefaultSoftwareRuntimeProbe::loadProcessSnapshot, DEFAULT_CACHE_TTL, System::nanoTime, DefaultSoftwareRuntimeProbe::runCommand);
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultSoftwareRuntimeProbe(
|
DefaultSoftwareRuntimeProbe(
|
||||||
Supplier<List<String>> processSnapshotLoader,
|
Supplier<List<String>> processSnapshotLoader,
|
||||||
Duration cacheTtl,
|
Duration cacheTtl,
|
||||||
LongSupplier nanoTimeSupplier
|
LongSupplier nanoTimeSupplier
|
||||||
|
) {
|
||||||
|
this(processSnapshotLoader, cacheTtl, nanoTimeSupplier, DefaultSoftwareRuntimeProbe::runCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
DefaultSoftwareRuntimeProbe(
|
||||||
|
Supplier<List<String>> processSnapshotLoader,
|
||||||
|
Duration cacheTtl,
|
||||||
|
LongSupplier nanoTimeSupplier,
|
||||||
|
CommandExitCodeSupplier commandExitCodeSupplier
|
||||||
) {
|
) {
|
||||||
this.processSnapshotLoader = Objects.requireNonNull(processSnapshotLoader, "processSnapshotLoader");
|
this.processSnapshotLoader = Objects.requireNonNull(processSnapshotLoader, "processSnapshotLoader");
|
||||||
this.cacheTtl = Objects.requireNonNull(cacheTtl, "cacheTtl");
|
this.cacheTtl = Objects.requireNonNull(cacheTtl, "cacheTtl");
|
||||||
this.nanoTimeSupplier = Objects.requireNonNull(nanoTimeSupplier, "nanoTimeSupplier");
|
this.nanoTimeSupplier = Objects.requireNonNull(nanoTimeSupplier, "nanoTimeSupplier");
|
||||||
|
this.commandExitCodeSupplier = Objects.requireNonNull(commandExitCodeSupplier, "commandExitCodeSupplier");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isRabbitmqRunning() {
|
public boolean isRabbitmqRunning() {
|
||||||
return isRunning("rabbitmq-server");
|
return commandSucceeds("bash", "-lc", "rabbitmqctl status >/dev/null 2>&1")
|
||||||
|
|| commandSucceeds("bash", "-lc", "systemctl is-active --quiet rabbitmq.service")
|
||||||
|
|| isRunningAny("beam.smp", "rabbitmq-server", "epmd");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTlqRunning() {
|
public boolean isTlqRunning() {
|
||||||
return isRunning("tonglink|TLQ");
|
return isRunningAny("tonglink", "tlq", "tlqremote");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTidbRunning() {
|
public boolean isTidbRunning() {
|
||||||
return isRunning("tidb-server");
|
return isRunningAny("tidb-server");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isNginxRunning() {
|
public boolean isNginxRunning() {
|
||||||
return isRunning("nginx");
|
return isRunningAny("nginx");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isStandardAppRunning() {
|
public boolean isStandardAppRunning() {
|
||||||
return isRunning("cmsp") && isRunning("cmtp");
|
return (commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmsp.service") || isRunningAny("cmsp"))
|
||||||
|
&& (commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmtp.service") || isRunningAny("cmtp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDirectAppRunning() {
|
public boolean isDirectAppRunning() {
|
||||||
return isRunning("cmep4d|CAE");
|
boolean pmts = commandSucceeds("bash", "-lc", "systemctl is-active --quiet pmts.service")
|
||||||
|
|| isRunningAny("pmts", "pmtsstat");
|
||||||
|
boolean cmcp = commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmcp.service")
|
||||||
|
|| isRunningAny("cmcp");
|
||||||
|
boolean cmsp = commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmsp.service")
|
||||||
|
|| isRunningAny("cmsp");
|
||||||
|
boolean cmtp = commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmtp.service")
|
||||||
|
|| isRunningAny("cmtp");
|
||||||
|
boolean cmtp4cae = commandSucceeds("bash", "-lc", "systemctl is-active --quiet cmtp4cae.service")
|
||||||
|
|| isRunningAny("cmtp4cae");
|
||||||
|
return pmts && cmcp && cmsp && cmtp && cmtp4cae;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isTmsRunning() {
|
public boolean isTmsRunning() {
|
||||||
return isRunning("tms-framework.jar");
|
return isRunningAny("tms-framework.jar");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isRunning(String pattern) {
|
private boolean isRunningAll(String... tokens) {
|
||||||
|
for (String token : tokens) {
|
||||||
|
if (!isRunningAny(token)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isRunningAny(String... tokens) {
|
||||||
try {
|
try {
|
||||||
Pattern compiled = Pattern.compile(pattern);
|
List<Pattern> patterns = compilePatterns(tokens);
|
||||||
return processSnapshot().stream().anyMatch(commandLine -> compiled.matcher(commandLine).find());
|
return processSnapshot().stream().anyMatch(commandLine -> matchesAny(commandLine, patterns));
|
||||||
} catch (PatternSyntaxException ex) {
|
} catch (PatternSyntaxException ex) {
|
||||||
throw new IllegalStateException("invalid process probe pattern: " + pattern, ex);
|
throw new IllegalStateException("invalid process probe tokens: " + String.join(",", tokens), ex);
|
||||||
} catch (RuntimeException ex) {
|
} catch (RuntimeException ex) {
|
||||||
throw new IllegalStateException("process probe failed: " + pattern, ex);
|
throw new IllegalStateException("process probe failed: " + String.join(",", tokens), ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Pattern> compilePatterns(String... tokens) {
|
||||||
|
return List.of(tokens).stream()
|
||||||
|
.filter(token -> token != null && !token.isBlank())
|
||||||
|
.map(this::compileTokenPattern)
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Pattern compileTokenPattern(String token) {
|
||||||
|
return Pattern.compile("(?i)(?<![a-z0-9])" + Pattern.quote(token.trim()) + "(?![a-z0-9])");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean matchesAny(String commandLine, List<Pattern> patterns) {
|
||||||
|
for (Pattern pattern : patterns) {
|
||||||
|
if (pattern.matcher(commandLine).find()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean commandSucceeds(String... command) {
|
||||||
|
try {
|
||||||
|
return commandExitCodeSupplier.get(command) == 0;
|
||||||
|
} catch (RuntimeException ex) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,6 +191,23 @@ public class DefaultSoftwareRuntimeProbe implements SoftwareRuntimeProbe {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int runCommand(String... command) {
|
||||||
|
try {
|
||||||
|
Process process = new ProcessBuilder(command).start();
|
||||||
|
return process.waitFor();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
throw new IllegalStateException("command interrupted", ex);
|
||||||
|
} catch (IOException ex) {
|
||||||
|
throw new IllegalStateException("command failed", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@FunctionalInterface
|
||||||
|
interface CommandExitCodeSupplier {
|
||||||
|
int get(String... command);
|
||||||
|
}
|
||||||
|
|
||||||
private record CachedProcessSnapshot(List<String> commandLines, long loadedAtNanos) {
|
private record CachedProcessSnapshot(List<String> commandLines, long loadedAtNanos) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -82,7 +82,19 @@ public class InitExecutorProperties {
|
|||||||
private String directDbScriptDir = "/opt/CAE_Install_Base_Resource/DB";
|
private String directDbScriptDir = "/opt/CAE_Install_Base_Resource/DB";
|
||||||
// 直参版 TLQ init_cfg.sh 脚本目录
|
// 直参版 TLQ init_cfg.sh 脚本目录
|
||||||
private String directTlqInitCfgDir = "/opt/CAE_Install_App_Resource/CAE";
|
private String directTlqInitCfgDir = "/opt/CAE_Install_App_Resource/CAE";
|
||||||
// CFMQ 配置落地目录(为空表示只做文件存在校验,不做拷贝)
|
// 直参版 CAE 客户化配置目标目录
|
||||||
|
private String directCaeTargetDir = "/pmts/cfg";
|
||||||
|
// 直参版 CAE 更新脚本目录
|
||||||
|
private String directCaeUpdateScriptDir = "/opt/CAE_Install_App_Resource/CAE";
|
||||||
|
// 直参版 CAE 更新命令
|
||||||
|
private String directCaeUpdateCommand = "bash ./cae_update.sh";
|
||||||
|
// TLQ 网关脚本目标目录
|
||||||
|
private String directTlqGatewayScriptTargetDir = "/home/tlq/bin";
|
||||||
|
// TLQ 重启命令
|
||||||
|
private String directTlqRestartCommand = "systemctl restart tonglinkmq.service";
|
||||||
|
// CFMQ 运行目录
|
||||||
|
private String directCfmqInstallPath = "/home/cfmq/dev/cfmq";
|
||||||
|
// CFMQ 配置落地目录(兼容旧实现)
|
||||||
private String cfmqTargetDir = "/pmts/cfg";
|
private String cfmqTargetDir = "/pmts/cfg";
|
||||||
// RabbitMQ 管理员账号(预制)
|
// RabbitMQ 管理员账号(预制)
|
||||||
private String rabbitAdminUsername = "admin";
|
private String rabbitAdminUsername = "admin";
|
||||||
@@ -392,6 +404,54 @@ public class InitExecutorProperties {
|
|||||||
this.directTlqLicenseTargetPath = directTlqLicenseTargetPath;
|
this.directTlqLicenseTargetPath = directTlqLicenseTargetPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getDirectCaeTargetDir() {
|
||||||
|
return directCaeTargetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectCaeTargetDir(String directCaeTargetDir) {
|
||||||
|
this.directCaeTargetDir = directCaeTargetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectCaeUpdateScriptDir() {
|
||||||
|
return directCaeUpdateScriptDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectCaeUpdateScriptDir(String directCaeUpdateScriptDir) {
|
||||||
|
this.directCaeUpdateScriptDir = directCaeUpdateScriptDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectCaeUpdateCommand() {
|
||||||
|
return directCaeUpdateCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectCaeUpdateCommand(String directCaeUpdateCommand) {
|
||||||
|
this.directCaeUpdateCommand = directCaeUpdateCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectTlqGatewayScriptTargetDir() {
|
||||||
|
return directTlqGatewayScriptTargetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectTlqGatewayScriptTargetDir(String directTlqGatewayScriptTargetDir) {
|
||||||
|
this.directTlqGatewayScriptTargetDir = directTlqGatewayScriptTargetDir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectTlqRestartCommand() {
|
||||||
|
return directTlqRestartCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectTlqRestartCommand(String directTlqRestartCommand) {
|
||||||
|
this.directTlqRestartCommand = directTlqRestartCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDirectCfmqInstallPath() {
|
||||||
|
return directCfmqInstallPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDirectCfmqInstallPath(String directCfmqInstallPath) {
|
||||||
|
this.directCfmqInstallPath = directCfmqInstallPath;
|
||||||
|
}
|
||||||
|
|
||||||
public String getCfmqTargetDir() {
|
public String getCfmqTargetDir() {
|
||||||
return cfmqTargetDir;
|
return cfmqTargetDir;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.cisd.tms.modules.init.dto;
|
package com.cisd.tms.modules.init.dto;
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
@Schema(description = "当前已初始化的 CISD 核心配置响应")
|
@Schema(description = "当前已初始化的 CISD 核心配置响应")
|
||||||
public class CurrentInitConfigResponse {
|
public class CurrentInitConfigResponse {
|
||||||
@@ -27,6 +29,12 @@ public class CurrentInitConfigResponse {
|
|||||||
private String node02Ip;
|
private String node02Ip;
|
||||||
@Schema(description = "CIPS 中心网关地址", example = "192.168.10.20")
|
@Schema(description = "CIPS 中心网关地址", example = "192.168.10.20")
|
||||||
private String cipsGatewayHost;
|
private String cipsGatewayHost;
|
||||||
|
@Schema(description = "TLQ 相关文件名列表,包含 TLQ License、TLQ 配置包等")
|
||||||
|
private List<String> tlqFileNames = new ArrayList<>();
|
||||||
|
@Schema(description = "CFMQ 相关文件名列表,包含 CFMQ 配置包、CFMQ 配置脚本等")
|
||||||
|
private List<String> cfmqFileNames = new ArrayList<>();
|
||||||
|
@Schema(description = "收发器 LICENSE 文件名", example = "receiver-license.dat")
|
||||||
|
private String receiverLicenseFileName;
|
||||||
|
|
||||||
public String getOrgCodeType() {
|
public String getOrgCodeType() {
|
||||||
return orgCodeType;
|
return orgCodeType;
|
||||||
@@ -115,4 +123,28 @@ public class CurrentInitConfigResponse {
|
|||||||
public void setCipsGatewayHost(String cipsGatewayHost) {
|
public void setCipsGatewayHost(String cipsGatewayHost) {
|
||||||
this.cipsGatewayHost = cipsGatewayHost;
|
this.cipsGatewayHost = cipsGatewayHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<String> getTlqFileNames() {
|
||||||
|
return tlqFileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTlqFileNames(List<String> tlqFileNames) {
|
||||||
|
this.tlqFileNames = tlqFileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<String> getCfmqFileNames() {
|
||||||
|
return cfmqFileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCfmqFileNames(List<String> cfmqFileNames) {
|
||||||
|
this.cfmqFileNames = cfmqFileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReceiverLicenseFileName() {
|
||||||
|
return receiverLicenseFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReceiverLicenseFileName(String receiverLicenseFileName) {
|
||||||
|
this.receiverLicenseFileName = receiverLicenseFileName;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package com.cisd.tms.modules.init.dto;
|
|||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.Max;
|
|
||||||
import jakarta.validation.constraints.Min;
|
|
||||||
import jakarta.validation.constraints.NotBlank;
|
import jakarta.validation.constraints.NotBlank;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import jakarta.validation.constraints.Pattern;
|
import jakarta.validation.constraints.Pattern;
|
||||||
@@ -51,14 +49,9 @@ public class InitPreviewRequest {
|
|||||||
private Mq mq;
|
private Mq mq;
|
||||||
|
|
||||||
@Valid
|
@Valid
|
||||||
@NotNull(message = "licenses is required")
|
|
||||||
@Schema(description = "初始化许可证与配置包引用")
|
@Schema(description = "初始化许可证与配置包引用")
|
||||||
private Licenses licenses;
|
private Licenses licenses;
|
||||||
|
|
||||||
@Valid
|
|
||||||
@Schema(description = "直连 TLQ 配置,直参版按需填写")
|
|
||||||
private DirectTlqConfig directTlq;
|
|
||||||
|
|
||||||
public String getOrgCodeType() {
|
public String getOrgCodeType() {
|
||||||
return orgCodeType;
|
return orgCodeType;
|
||||||
}
|
}
|
||||||
@@ -123,14 +116,6 @@ public class InitPreviewRequest {
|
|||||||
this.licenses = licenses;
|
this.licenses = licenses;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DirectTlqConfig getDirectTlq() {
|
|
||||||
return directTlq;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDirectTlq(DirectTlqConfig directTlq) {
|
|
||||||
this.directTlq = directTlq;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Schema(description = "节点 IP 配置")
|
@Schema(description = "节点 IP 配置")
|
||||||
public static class Nodes {
|
public static class Nodes {
|
||||||
|
|
||||||
@@ -193,28 +178,34 @@ public class InitPreviewRequest {
|
|||||||
|
|
||||||
@NotBlank(message = "mq.channelUsername is required")
|
@NotBlank(message = "mq.channelUsername is required")
|
||||||
@Size(max = 32, message = "mq.channelUsername length must be <= 32")
|
@Size(max = 32, message = "mq.channelUsername length must be <= 32")
|
||||||
@Schema(description = "通道用户名", example = "tms")
|
@Schema(description = "RABBITMQ通道用户名", example = "tms")
|
||||||
private String channelUsername;
|
private String channelUsername;
|
||||||
|
|
||||||
@NotBlank(message = "mq.channelPassword is required")
|
@NotBlank(message = "mq.channelPassword is required")
|
||||||
@Size(max = 128, message = "mq.channelPassword length must be <= 128")
|
@Size(max = 128, message = "mq.channelPassword length must be <= 128")
|
||||||
@Schema(description = "通道密码")
|
@Schema(description = "RABBITMQ通道密码")
|
||||||
private String channelPassword;
|
private String channelPassword;
|
||||||
|
|
||||||
@Size(max = 128, message = "mq.tlqLicenseFileId length must be <= 128")
|
@Size(max = 128, message = "mq.tlqLicenseFileId length must be <= 128")
|
||||||
@Pattern(regexp = FILE_ID_REGEX, message = "mq.tlqLicenseFileId must be a fileId")
|
@Pattern(regexp = FILE_ID_REGEX, message = "mq.tlqLicenseFileId must be a fileId")
|
||||||
@Schema(description = "TLQ 许可证文件 fileId", example = "FILE-20260310-000001")
|
@Schema(description = "TLQ 许可证文件 fileId。作用:用于 TLQ 相关模式的许可证下发。使用条件:`TLQ` 或 `RABBITMQ_TLQ` 场景必填", example = "FILE-20260310-000001")
|
||||||
private String tlqLicenseFileId;
|
private String tlqLicenseFileId;
|
||||||
|
|
||||||
|
@Size(max = 64, message = "mq.cipsGatewayHost length must be <= 64")
|
||||||
|
@Schema(description = "CIPS 中心网关地址。作用:回写到 TLQ 网关脚本中的中心网关主机地址。使用条件:仅 `DIRECT + RABBITMQ_TLQ` 必填", example = "192.168.10.20")
|
||||||
|
private String cipsGatewayHost;
|
||||||
|
|
||||||
|
@Size(max = 128, message = "mq.cfgZipFileId length must be <= 128")
|
||||||
|
@Pattern(regexp = FILE_ID_REGEX, message = "mq.cfgZipFileId must be a fileId")
|
||||||
|
@Schema(description = "直参 PMTS-CAE 客户化配置包 fileId。使用条件:仅 `DIRECT` 使用;`RABBITMQ_TLQ`必填", example = "FILE-20260310-000201")
|
||||||
|
private String cfgZipFileId;
|
||||||
|
|
||||||
|
|
||||||
@Size(max = 128, message = "mq.cfmqConfigFileId length must be <= 128")
|
@Size(max = 128, message = "mq.cfmqConfigFileId length must be <= 128")
|
||||||
@Pattern(regexp = FILE_ID_REGEX, message = "mq.cfmqConfigFileId must be a fileId")
|
@Pattern(regexp = FILE_ID_REGEX, message = "mq.cfmqConfigFileId must be a fileId")
|
||||||
@Schema(description = "CFMQ 配置文件 fileId", example = "FILE-20260310-000002")
|
@Schema(description = "直参 CFMQ 客户化脚本/配置 fileId。使用条件:仅 `DIRECT + RABBITMQ_CFMQ` 必填", example = "FILE-20260310-000002")
|
||||||
private String cfmqConfigFileId;
|
private String cfmqConfigFileId;
|
||||||
|
|
||||||
@Size(max = 64, message = "mq.cipsGatewayHost length must be <= 64")
|
|
||||||
@Schema(description = "CIPS 中心网关地址,仅 DIRECT + RABBITMQ_TLQ 使用", example = "192.168.10.20")
|
|
||||||
private String cipsGatewayHost;
|
|
||||||
|
|
||||||
public String getMqType() {
|
public String getMqType() {
|
||||||
return mqType;
|
return mqType;
|
||||||
}
|
}
|
||||||
@@ -262,6 +253,15 @@ public class InitPreviewRequest {
|
|||||||
public void setCipsGatewayHost(String cipsGatewayHost) {
|
public void setCipsGatewayHost(String cipsGatewayHost) {
|
||||||
this.cipsGatewayHost = cipsGatewayHost;
|
this.cipsGatewayHost = cipsGatewayHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getCfgZipFileId() {
|
||||||
|
return cfgZipFileId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCfgZipFileId(String cfgZipFileId) {
|
||||||
|
this.cfgZipFileId = cfgZipFileId;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "许可证和配置包引用")
|
@Schema(description = "许可证和配置包引用")
|
||||||
@@ -275,7 +275,7 @@ public class InitPreviewRequest {
|
|||||||
|
|
||||||
@Size(max = 128, message = "licenses.cfgZipFileId length must be <= 128")
|
@Size(max = 128, message = "licenses.cfgZipFileId length must be <= 128")
|
||||||
@Pattern(regexp = FILE_ID_REGEX, message = "licenses.cfgZipFileId must be a fileId")
|
@Pattern(regexp = FILE_ID_REGEX, message = "licenses.cfgZipFileId must be a fileId")
|
||||||
@Schema(description = "标准版配置包 zip 文件 fileId", example = "FILE-20260310-000004")
|
@Schema(description = "标准版配置包 zip 文件 fileId。作用:用于标准版/间参版初始化时引用配置包。使用条件:`ENTERPRISE`、`INDIRECT` 场景按对应流程使用,`DIRECT` 不使用此字段", example = "FILE-20260310-000004")
|
||||||
private String cfgZipFileId;
|
private String cfgZipFileId;
|
||||||
|
|
||||||
public String getReceiverLicenseFileId() {
|
public String getReceiverLicenseFileId() {
|
||||||
@@ -294,45 +294,4 @@ public class InitPreviewRequest {
|
|||||||
this.cfgZipFileId = cfgZipFileId;
|
this.cfgZipFileId = cfgZipFileId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Schema(description = "直连 TLQ 配置")
|
|
||||||
public static class DirectTlqConfig {
|
|
||||||
|
|
||||||
@Pattern(regexp = "A|B", message = "directTlq.localNodeSeq must be A/B")
|
|
||||||
@Schema(description = "本节点序号", example = "A")
|
|
||||||
private String localNodeSeq;
|
|
||||||
|
|
||||||
@Size(max = 256, message = "directTlq.upstreamInstitutions length must be <= 256")
|
|
||||||
@Schema(description = "上游机构列表", example = "BANKA,BANKB")
|
|
||||||
private String upstreamInstitutions;
|
|
||||||
|
|
||||||
@Min(value = 1, message = "directTlq.upstreamCocCount must be >= 1")
|
|
||||||
@Max(value = 2, message = "directTlq.upstreamCocCount must be <= 2")
|
|
||||||
@Schema(description = "上游 COC 数量", example = "2")
|
|
||||||
private Integer upstreamCocCount;
|
|
||||||
|
|
||||||
public String getLocalNodeSeq() {
|
|
||||||
return localNodeSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLocalNodeSeq(String localNodeSeq) {
|
|
||||||
this.localNodeSeq = localNodeSeq;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getUpstreamInstitutions() {
|
|
||||||
return upstreamInstitutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpstreamInstitutions(String upstreamInstitutions) {
|
|
||||||
this.upstreamInstitutions = upstreamInstitutions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getUpstreamCocCount() {
|
|
||||||
return upstreamCocCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUpstreamCocCount(Integer upstreamCocCount) {
|
|
||||||
this.upstreamCocCount = upstreamCocCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+260
-156
@@ -149,7 +149,12 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
case "verify_reset" -> executeVerifyReset(task, step);
|
case "verify_reset" -> executeVerifyReset(task, step);
|
||||||
case "direct_db_init" -> executeDirectDbInit(task, step);
|
case "direct_db_init" -> executeDirectDbInit(task, step);
|
||||||
case "tlq_init_cfg" -> executeTlqInitCfg(task, step);
|
case "tlq_init_cfg" -> executeTlqInitCfg(task, step);
|
||||||
case "cfmq_apply" -> executeCfmqApply(task, step);
|
case "cae_package_apply" -> executeCaePackageApply(task, step);
|
||||||
|
case "cae_update" -> executeCaeUpdate(task, step);
|
||||||
|
case "tlq_gateway_apply" -> executeTlqGatewayApply(task, step);
|
||||||
|
case "restart_tlq" -> executeRestartTlq(task, step);
|
||||||
|
case "cfmq_link_apply", "cfmq_apply" -> executeCfmqLinkApply(task, step);
|
||||||
|
case "cfmq_route_apply" -> executeCfmqRouteApply(task, step);
|
||||||
case "verify" -> executeVerify(task, step);
|
case "verify" -> executeVerify(task, step);
|
||||||
default -> {
|
default -> {
|
||||||
String logPath = writeInternalLog(task, step, "skip unsupported internal step: " + internalCode);
|
String logPath = writeInternalLog(task, step, "skip unsupported internal step: " + internalCode);
|
||||||
@@ -177,6 +182,18 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
: buildStandardReplacements(context);
|
: buildStandardReplacements(context);
|
||||||
int changed = replaceConfigValues(cpconfigPath, replacements);
|
int changed = replaceConfigValues(cpconfigPath, replacements);
|
||||||
String message = "cpconfig rendered, path=" + cpconfigPath + ", changedKeys=" + changed;
|
String message = "cpconfig rendered, path=" + cpconfigPath + ", changedKeys=" + changed;
|
||||||
|
if ("DIRECT".equals(context.productType())) {
|
||||||
|
Path targetCpconfigPath = Paths.get(firstNonBlank(properties.getDirectCpconfigTargetPath(), "/opt/cpconfig.cfg"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
if (targetCpconfigPath.getParent() != null) {
|
||||||
|
Files.createDirectories(targetCpconfigPath.getParent());
|
||||||
|
}
|
||||||
|
if (!cpconfigPath.equals(targetCpconfigPath)) {
|
||||||
|
Files.copy(cpconfigPath, targetCpconfigPath, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
message = message + ", syncedTarget=" + targetCpconfigPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
String logPath = writeInternalLog(task, step, message);
|
String logPath = writeInternalLog(task, step, message);
|
||||||
return InitStepExecutionResult.success(message, 0, logPath);
|
return InitStepExecutionResult.success(message, 0, logPath);
|
||||||
}
|
}
|
||||||
@@ -794,57 +811,8 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
String logPath = writeInternalLog(task, step, "direct_db_init skipped for non-direct product type");
|
String logPath = writeInternalLog(task, step, "direct_db_init skipped for non-direct product type");
|
||||||
return InitStepExecutionResult.success("direct_db_init skipped", 0, logPath);
|
return InitStepExecutionResult.success("direct_db_init skipped", 0, logPath);
|
||||||
}
|
}
|
||||||
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
String logPath = writeInternalLog(task, step, "direct_db_init skipped: out of direct customer-config scope");
|
||||||
String logPath = writeInternalLog(task, step, "direct_db_init simulated");
|
return InitStepExecutionResult.success("direct_db_init skipped", 0, logPath);
|
||||||
return InitStepExecutionResult.success("direct_db_init simulated", 0, logPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path scriptDir = Paths.get(firstNonBlank(properties.getDirectDbScriptDir(), "/opt/CAE_Install_Base_Resource/DB"))
|
|
||||||
.normalize()
|
|
||||||
.toAbsolutePath();
|
|
||||||
if (!Files.isDirectory(scriptDir)) {
|
|
||||||
String logPath = writeInternalLog(task, step, "direct_db_init failed: script dir not found: " + scriptDir);
|
|
||||||
return InitStepExecutionResult.failure("direct_db_init failed: script dir not found", -1, logPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
ResolvedCpconfig resolvedCpconfig = resolveCpconfigPath(task, context);
|
|
||||||
Path cpconfigPath = resolvedCpconfig.path();
|
|
||||||
if (!Files.exists(cpconfigPath) || !Files.isRegularFile(cpconfigPath)) {
|
|
||||||
String logPath = writeInternalLog(
|
|
||||||
task,
|
|
||||||
step,
|
|
||||||
"direct_db_init failed: cpconfig not found: " + cpconfigPath
|
|
||||||
+ ", candidates=" + formatPathList(resolvedCpconfig.candidates())
|
|
||||||
);
|
|
||||||
return InitStepExecutionResult.failure("direct_db_init failed: cpconfig not found", -1, logPath);
|
|
||||||
}
|
|
||||||
Path targetCpconfigPath = Paths.get(firstNonBlank(properties.getDirectCpconfigTargetPath(), "/opt/cpconfig.cfg"))
|
|
||||||
.normalize()
|
|
||||||
.toAbsolutePath();
|
|
||||||
|
|
||||||
try {
|
|
||||||
Path logFile = prepareLogPath(task, step);
|
|
||||||
if (targetCpconfigPath.getParent() != null) {
|
|
||||||
Files.createDirectories(targetCpconfigPath.getParent());
|
|
||||||
}
|
|
||||||
Files.copy(cpconfigPath, targetCpconfigPath, StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
appendLog(logFile, "cpconfig prepared: " + cpconfigPath + " -> " + targetCpconfigPath);
|
|
||||||
|
|
||||||
int code = runCommand(
|
|
||||||
logFile,
|
|
||||||
Arrays.asList("bash", "./setsql.sh"),
|
|
||||||
false,
|
|
||||||
scriptDir
|
|
||||||
);
|
|
||||||
if (code != 0) {
|
|
||||||
return InitStepExecutionResult.failure("direct_db_init failed", code, logFile.toString());
|
|
||||||
}
|
|
||||||
return InitStepExecutionResult.success("direct db init applied", 0, logFile.toString());
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
Thread.currentThread().interrupt();
|
|
||||||
String logPath = writeInternalLog(task, step, "direct_db_init interrupted");
|
|
||||||
return InitStepExecutionResult.failure("direct_db_init interrupted", -1, logPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private InitStepExecutionResult executeStandardDbRender(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
private InitStepExecutionResult executeStandardDbRender(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
@@ -1229,83 +1197,197 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg skipped for non-direct TLQ mode");
|
String logPath = writeInternalLog(task, step, "tlq_init_cfg skipped for non-direct TLQ mode");
|
||||||
return InitStepExecutionResult.success("tlq_init_cfg skipped", 0, logPath);
|
return InitStepExecutionResult.success("tlq_init_cfg skipped", 0, logPath);
|
||||||
}
|
}
|
||||||
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
String logPath = writeInternalLog(task, step, "tlq_init_cfg skipped: no longer part of direct customer-config scope");
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg simulated");
|
return InitStepExecutionResult.success("tlq_init_cfg skipped", 0, logPath);
|
||||||
return InitStepExecutionResult.success("tlq_init_cfg simulated", 0, logPath);
|
}
|
||||||
|
|
||||||
|
private InitStepExecutionResult executeCaePackageApply(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
|
PlanContext context = loadPlanContext(task);
|
||||||
|
if (!"DIRECT".equals(context.productType())) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cae_package_apply skipped for non-direct product type");
|
||||||
|
return InitStepExecutionResult.success("cae_package_apply skipped", 0, logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
String localNodeSeq = normalizeUpper(context.directTlqLocalNodeSeq());
|
Path zipFile = resolveAndStageInputFile(task, context.cfgZipFileId(), "cae_package", null);
|
||||||
String upstreamInstitutions = normalize(context.directTlqUpstreamInstitutions());
|
Path unpackDir = resolveDirectStageDir(task, "cae/unpacked");
|
||||||
Integer upstreamCocCount = context.directTlqUpstreamCocCount();
|
recreateDirectory(unpackDir);
|
||||||
if (!"A".equals(localNodeSeq) && !"B".equals(localNodeSeq)) {
|
unzipToDirectory(zipFile, unpackDir);
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg failed: localNodeSeq must be A/B");
|
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg failed: invalid localNodeSeq", -1, logPath);
|
|
||||||
}
|
|
||||||
if (isBlank(upstreamInstitutions)) {
|
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg failed: upstreamInstitutions is blank");
|
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg failed: upstreamInstitutions is blank", -1, logPath);
|
|
||||||
}
|
|
||||||
if (upstreamCocCount == null || upstreamCocCount < 1 || upstreamCocCount > 2) {
|
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg failed: upstreamCocCount must be in [1,2]");
|
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg failed: invalid upstreamCocCount", -1, logPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
Path scriptDir = Paths.get(firstNonBlank(properties.getDirectTlqInitCfgDir(), "/opt/CAE_Install_App_Resource/CAE"))
|
Path targetDir = Paths.get(firstNonBlank(properties.getDirectCaeTargetDir(), properties.getCfmqTargetDir()))
|
||||||
.normalize()
|
.normalize()
|
||||||
.toAbsolutePath();
|
.toAbsolutePath();
|
||||||
if (!Files.isDirectory(scriptDir)) {
|
Files.createDirectories(targetDir);
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg failed: script dir not found: " + scriptDir);
|
copyDirectoryContents(unpackDir, targetDir);
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg failed: script dir not found", -1, logPath);
|
|
||||||
|
String message = "cae package applied: " + zipFile + " -> " + targetDir;
|
||||||
|
String logPath = writeInternalLog(task, step, message);
|
||||||
|
return InitStepExecutionResult.success(message, 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitStepExecutionResult executeCaeUpdate(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
|
PlanContext context = loadPlanContext(task);
|
||||||
|
if (!"DIRECT".equals(context.productType())) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cae_update skipped for non-direct product type");
|
||||||
|
return InitStepExecutionResult.success("cae_update skipped", 0, logPath);
|
||||||
|
}
|
||||||
|
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cae_update simulated");
|
||||||
|
return InitStepExecutionResult.success("cae_update simulated", 0, logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String command = normalize(properties.getDirectCaeUpdateCommand());
|
||||||
|
if (isBlank(command)) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cae_update validated only: command is blank");
|
||||||
|
return InitStepExecutionResult.success("cae_update validated", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path scriptDir = Paths.get(firstNonBlank(properties.getDirectCaeUpdateScriptDir(), "/opt/CAE_Install_App_Resource/CAE"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
Path logFile = prepareLogPath(task, step);
|
||||||
try {
|
try {
|
||||||
Path logFile = prepareLogPath(task, step);
|
int code = runCommand(logFile, Arrays.asList("/bin/zsh", "-lc", command), false, scriptDir);
|
||||||
int code = runCommand(
|
|
||||||
logFile,
|
|
||||||
Arrays.asList(
|
|
||||||
"bash",
|
|
||||||
"./init_cfg.sh",
|
|
||||||
normalize(context.orgCode()),
|
|
||||||
localNodeSeq,
|
|
||||||
"TLQ",
|
|
||||||
upstreamInstitutions,
|
|
||||||
String.valueOf(upstreamCocCount)
|
|
||||||
),
|
|
||||||
false,
|
|
||||||
scriptDir
|
|
||||||
);
|
|
||||||
if (code != 0) {
|
if (code != 0) {
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg failed", code, logFile.toString());
|
return InitStepExecutionResult.failure("cae_update failed", code, logFile.toString());
|
||||||
}
|
}
|
||||||
return InitStepExecutionResult.success("tlq_init_cfg applied", 0, logFile.toString());
|
return InitStepExecutionResult.success("cae_update applied", 0, logFile.toString());
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
String logPath = writeInternalLog(task, step, "tlq_init_cfg interrupted");
|
return InitStepExecutionResult.failure("cae_update interrupted", -1, logFile.toString());
|
||||||
return InitStepExecutionResult.failure("tlq_init_cfg interrupted", -1, logPath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private InitStepExecutionResult executeCfmqApply(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
private InitStepExecutionResult executeTlqGatewayApply(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
|
PlanContext context = loadPlanContext(task);
|
||||||
|
if (!"DIRECT".equals(context.productType()) || !"RABBITMQ_TLQ".equals(context.mqType())) {
|
||||||
|
String logPath = writeInternalLog(task, step, "tlq_gateway_apply skipped for non-direct TLQ mode");
|
||||||
|
return InitStepExecutionResult.success("tlq_gateway_apply skipped", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path sourceScript = resolveTlqGatewaySourceScript(task);
|
||||||
|
if (!Files.exists(sourceScript) || !Files.isRegularFile(sourceScript)) {
|
||||||
|
String logPath = writeInternalLog(task, step, "tlq_gateway_apply failed: source script not found: " + sourceScript);
|
||||||
|
return InitStepExecutionResult.failure("tlq_gateway_apply failed: source script not found", -1, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
String rewritten = rewriteGatewayHost(Files.readString(sourceScript), context.cipsGatewayHost());
|
||||||
|
Path targetDir = Paths.get(firstNonBlank(properties.getDirectTlqGatewayScriptTargetDir(), "/home/tlq/bin"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
Files.createDirectories(targetDir);
|
||||||
|
Path targetScript = targetDir.resolve(sourceScript.getFileName());
|
||||||
|
Files.writeString(targetScript, rewritten, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
|
||||||
|
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
||||||
|
String logPath = writeInternalLog(task, step, "tlq_gateway_apply simulated: " + targetScript);
|
||||||
|
return InitStepExecutionResult.success("tlq_gateway_apply simulated", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path logFile = prepareLogPath(task, step);
|
||||||
|
try {
|
||||||
|
int code = runCommand(logFile, Arrays.asList("bash", targetScript.toString()), false);
|
||||||
|
if (code != 0) {
|
||||||
|
return InitStepExecutionResult.failure("tlq_gateway_apply failed", code, logFile.toString());
|
||||||
|
}
|
||||||
|
return InitStepExecutionResult.success("tlq gateway applied: " + targetScript, 0, logFile.toString());
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return InitStepExecutionResult.failure("tlq_gateway_apply interrupted", -1, logFile.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitStepExecutionResult executeRestartTlq(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
|
PlanContext context = loadPlanContext(task);
|
||||||
|
if (!"DIRECT".equals(context.productType()) || !"RABBITMQ_TLQ".equals(context.mqType())) {
|
||||||
|
String logPath = writeInternalLog(task, step, "restart_tlq skipped for non-direct TLQ mode");
|
||||||
|
return InitStepExecutionResult.success("restart_tlq skipped", 0, logPath);
|
||||||
|
}
|
||||||
|
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
||||||
|
String logPath = writeInternalLog(task, step, "restart_tlq simulated");
|
||||||
|
return InitStepExecutionResult.success("restart_tlq simulated", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
String command = normalize(properties.getDirectTlqRestartCommand());
|
||||||
|
if (isBlank(command)) {
|
||||||
|
String logPath = writeInternalLog(task, step, "restart_tlq validated only: command is blank");
|
||||||
|
return InitStepExecutionResult.success("restart_tlq validated", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path logFile = prepareLogPath(task, step);
|
||||||
|
try {
|
||||||
|
int code = runCommand(logFile, Arrays.asList("/bin/zsh", "-lc", command), false);
|
||||||
|
if (code != 0) {
|
||||||
|
return InitStepExecutionResult.failure("restart_tlq failed", code, logFile.toString());
|
||||||
|
}
|
||||||
|
return InitStepExecutionResult.success("restart_tlq applied", 0, logFile.toString());
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return InitStepExecutionResult.failure("restart_tlq interrupted", -1, logFile.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitStepExecutionResult executeCfmqLinkApply(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
PlanContext context = loadPlanContext(task);
|
PlanContext context = loadPlanContext(task);
|
||||||
if (!"DIRECT".equals(context.productType()) || !"RABBITMQ_CFMQ".equals(context.mqType())) {
|
if (!"DIRECT".equals(context.productType()) || !"RABBITMQ_CFMQ".equals(context.mqType())) {
|
||||||
String logPath = writeInternalLog(task, step, "mq is not RABBITMQ_CFMQ, cfmq_apply skipped");
|
String logPath = writeInternalLog(task, step, "cfmq_link_apply skipped for non-direct CFMQ mode");
|
||||||
return InitStepExecutionResult.success("cfmq_apply skipped", 0, logPath);
|
return InitStepExecutionResult.success("cfmq_link_apply skipped", 0, logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path source = resolveAndStageInputFile(task, context.cfmqConfigFileId(), "cfmq_config", null);
|
Path sourceScript = resolveAndStageInputFile(task, context.cfmqConfigFileId(), "cfmq_link_script", null);
|
||||||
String targetDirValue = normalize(properties.getCfmqTargetDir());
|
String rewritten = Files.readString(sourceScript)
|
||||||
if (isBlank(targetDirValue)) {
|
.replace("/cfmq/cfmq-server", normalize(properties.getDirectCfmqInstallPath()));
|
||||||
String logPath = writeInternalLog(task, step, "cfmq config validated only: " + source);
|
Path stagedScript = resolveDirectStageDir(task, "cfmq/link").resolve(sourceScript.getFileName());
|
||||||
return InitStepExecutionResult.success("cfmq config validated", 0, logPath);
|
Files.createDirectories(stagedScript.getParent());
|
||||||
|
Files.writeString(stagedScript, rewritten, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
|
||||||
|
|
||||||
|
if (properties.getMode() == InitExecutorProperties.Mode.SIMULATE) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cfmq_link_apply simulated: " + stagedScript);
|
||||||
|
return InitStepExecutionResult.success("cfmq_link_apply simulated", 0, logPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
Path targetDir = Paths.get(targetDirValue).normalize().toAbsolutePath();
|
Path logFile = prepareLogPath(task, step);
|
||||||
Files.createDirectories(targetDir);
|
try {
|
||||||
Path target = targetDir.resolve(source.getFileName());
|
int code = runCommand(logFile, Arrays.asList("bash", stagedScript.toString()), false);
|
||||||
Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
|
if (code != 0) {
|
||||||
String message = "cfmq config applied: " + source + " -> " + target;
|
return InitStepExecutionResult.failure("cfmq_link_apply failed", code, logFile.toString());
|
||||||
String logPath = writeInternalLog(task, step, message);
|
}
|
||||||
return InitStepExecutionResult.success(message, 0, logPath);
|
return InitStepExecutionResult.success("cfmq_link_apply applied", 0, logFile.toString());
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
return InitStepExecutionResult.failure("cfmq_link_apply interrupted", -1, logFile.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitStepExecutionResult executeCfmqRouteApply(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
|
PlanContext context = loadPlanContext(task);
|
||||||
|
if (!"DIRECT".equals(context.productType()) || !"RABBITMQ_CFMQ".equals(context.mqType())) {
|
||||||
|
String logPath = writeInternalLog(task, step, "cfmq_route_apply skipped for non-direct CFMQ mode");
|
||||||
|
return InitStepExecutionResult.success("cfmq_route_apply skipped", 0, logPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
Path targetDir = Paths.get(firstNonBlank(properties.getDirectCaeTargetDir(), properties.getCfmqTargetDir()))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
Path logFile = prepareLogPath(task, step);
|
||||||
|
int routeChanged = 0;
|
||||||
|
try (Stream<Path> stream = Files.walk(targetDir)) {
|
||||||
|
for (Path item : stream.filter(Files::isRegularFile).toList()) {
|
||||||
|
String fileName = item.getFileName() == null ? "" : item.getFileName().toString();
|
||||||
|
if (fileName.startsWith("route_") && fileName.endsWith(".ini")) {
|
||||||
|
String content = Files.readString(item);
|
||||||
|
String rewritten = content.replace("MSGMB_1", "MSGTOMB_1");
|
||||||
|
if (!rewritten.equals(content)) {
|
||||||
|
Files.writeString(item, rewritten, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE);
|
||||||
|
routeChanged++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Path pmtsMsgHdl = targetDir.resolve("pmtsmsghdl.cfg");
|
||||||
|
Files.deleteIfExists(pmtsMsgHdl);
|
||||||
|
appendLog(logFile, "cfmq route files changed=" + routeChanged + ", pmtsmsghdl deleted if exists=" + pmtsMsgHdl);
|
||||||
|
return InitStepExecutionResult.success("cfmq_route_apply applied", 0, logFile.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
private InitStepExecutionResult executeVerify(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
private InitStepExecutionResult executeVerify(InitTaskEntity task, InitTaskStepEntity step) throws IOException {
|
||||||
@@ -1363,12 +1445,6 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
private void verifyDirect(Map<String, String> configMap, PlanContext context, List<String> failures) {
|
private void verifyDirect(Map<String, String> configMap, PlanContext context, List<String> failures) {
|
||||||
requireNotBlank(configMap, "MQ_TYPE", failures);
|
requireNotBlank(configMap, "MQ_TYPE", failures);
|
||||||
requireNotBlank(configMap, "node_01_ip", failures);
|
requireNotBlank(configMap, "node_01_ip", failures);
|
||||||
requireNotBlank(configMap, "db_ip", failures);
|
|
||||||
requireNotBlank(configMap, "sign_host", failures);
|
|
||||||
requireNotBlank(configMap, "sign_port", failures);
|
|
||||||
requireNotBlank(configMap, "sign_type", failures);
|
|
||||||
requireNotBlank(configMap, "sign_cert_dn", failures);
|
|
||||||
requireNotBlank(configMap, "sign_cert_sn", failures);
|
|
||||||
|
|
||||||
if ("DUAL".equals(context.deployMode()) || "QUAD".equals(context.deployMode())) {
|
if ("DUAL".equals(context.deployMode()) || "QUAD".equals(context.deployMode())) {
|
||||||
requireNotBlank(configMap, "node_02_ip", failures);
|
requireNotBlank(configMap, "node_02_ip", failures);
|
||||||
@@ -1432,13 +1508,6 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
replacements.put("node_02_ip", node02);
|
replacements.put("node_02_ip", node02);
|
||||||
replacements.put("node_03_ip", node03);
|
replacements.put("node_03_ip", node03);
|
||||||
replacements.put("node_04_ip", node04);
|
replacements.put("node_04_ip", node04);
|
||||||
replacements.put("db_ip", node01);
|
|
||||||
replacements.put("sign_host", context.signHost());
|
|
||||||
replacements.put("sign_port", context.signPort() == null ? "" : String.valueOf(context.signPort()));
|
|
||||||
replacements.put("sign_password", quoteShellValue(context.signPassword()));
|
|
||||||
replacements.put("sign_type", context.signType());
|
|
||||||
replacements.put("sign_cert_dn", quoteShellValue(context.signCertDn()));
|
|
||||||
replacements.put("sign_cert_sn", context.signCertSn());
|
|
||||||
fillOrgCodeMappings(context, replacements);
|
fillOrgCodeMappings(context, replacements);
|
||||||
return replacements;
|
return replacements;
|
||||||
}
|
}
|
||||||
@@ -1531,6 +1600,12 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ResolvedCpconfig resolveCpconfigPath(InitTaskEntity task, PlanContext context) throws IOException {
|
private ResolvedCpconfig resolveCpconfigPath(InitTaskEntity task, PlanContext context) throws IOException {
|
||||||
|
if ("DIRECT".equals(context.productType())) {
|
||||||
|
Path stagedCpconfig = resolveDirectStageCpconfigPath(task);
|
||||||
|
if (Files.exists(stagedCpconfig) && Files.isRegularFile(stagedCpconfig)) {
|
||||||
|
return new ResolvedCpconfig(stagedCpconfig, List.of(stagedCpconfig));
|
||||||
|
}
|
||||||
|
}
|
||||||
List<Path> candidates = buildCpconfigCandidates(context);
|
List<Path> candidates = buildCpconfigCandidates(context);
|
||||||
if (candidates.isEmpty()) {
|
if (candidates.isEmpty()) {
|
||||||
Path uploadBase = Paths.get(firstNonBlank(properties.getUploadBaseDir(), "/home/tms/uploads"))
|
Path uploadBase = Paths.get(firstNonBlank(properties.getUploadBaseDir(), "/home/tms/uploads"))
|
||||||
@@ -1541,7 +1616,7 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
for (Path candidate : candidates) {
|
for (Path candidate : candidates) {
|
||||||
if (Files.exists(candidate) && Files.isRegularFile(candidate)) {
|
if (Files.exists(candidate) && Files.isRegularFile(candidate)) {
|
||||||
Path cpconfig = candidate;
|
Path cpconfig = candidate;
|
||||||
if ("DIRECT".equals(context.productType()) && !isBlank(context.cfgZipFileId())) {
|
if ("DIRECT".equals(context.productType())) {
|
||||||
cpconfig = stageFile(task, "cpconfig", firstNonBlank(properties.getDirectCpconfigFileName(), "cpconfig.cfg"), candidate);
|
cpconfig = stageFile(task, "cpconfig", firstNonBlank(properties.getDirectCpconfigFileName(), "cpconfig.cfg"), candidate);
|
||||||
}
|
}
|
||||||
return new ResolvedCpconfig(cpconfig, candidates);
|
return new ResolvedCpconfig(cpconfig, candidates);
|
||||||
@@ -1550,10 +1625,27 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
return new ResolvedCpconfig(candidates.get(0), candidates);
|
return new ResolvedCpconfig(candidates.get(0), candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Path resolveDirectStageCpconfigPath(InitTaskEntity task) {
|
||||||
|
Path stageRoot = Paths.get(firstNonBlank(properties.getStagingRootDir(), "/tmp/tms-init-staging"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
return stageRoot.resolve(task.getTaskId())
|
||||||
|
.resolve("inputs")
|
||||||
|
.resolve("cpconfig")
|
||||||
|
.resolve(firstNonBlank(properties.getDirectCpconfigFileName(), "cpconfig.cfg"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
private List<Path> buildCpconfigCandidates(PlanContext context) {
|
private List<Path> buildCpconfigCandidates(PlanContext context) {
|
||||||
String cpconfigFileName = firstNonBlank(properties.getDirectCpconfigFileName(), "cpconfig.cfg");
|
String cpconfigFileName = firstNonBlank(properties.getDirectCpconfigFileName(), "cpconfig.cfg");
|
||||||
if ("DIRECT".equals(context.productType())) {
|
if ("DIRECT".equals(context.productType())) {
|
||||||
return buildFileIdCandidates(context.cfgZipFileId(), cpconfigFileName);
|
List<Path> candidates = new ArrayList<>();
|
||||||
|
addAbsoluteCandidate(candidates, properties.getDirectCpconfigTargetPath());
|
||||||
|
addAbsoluteCandidate(candidates, Paths.get(firstNonBlank(properties.getDirectCpconfigTargetPath(), "/opt/cpconfig.cfg"))
|
||||||
|
.resolveSibling(cpconfigFileName)
|
||||||
|
.toString());
|
||||||
|
return deduplicatePaths(candidates);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Path> candidates = new ArrayList<>();
|
List<Path> candidates = new ArrayList<>();
|
||||||
@@ -2024,18 +2116,6 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
JsonNode nodes = request.path("nodes");
|
JsonNode nodes = request.path("nodes");
|
||||||
JsonNode mq = request.path("mq");
|
JsonNode mq = request.path("mq");
|
||||||
JsonNode licenses = request.path("licenses");
|
JsonNode licenses = request.path("licenses");
|
||||||
JsonNode signServer = request.path("signServer");
|
|
||||||
JsonNode directTlq = request.path("directTlq");
|
|
||||||
|
|
||||||
Integer signPort = null;
|
|
||||||
if (!signServer.path("signPort").isMissingNode() && !signServer.path("signPort").isNull()) {
|
|
||||||
signPort = signServer.path("signPort").asInt();
|
|
||||||
}
|
|
||||||
Integer directTlqUpstreamCocCount = null;
|
|
||||||
if (!directTlq.path("upstreamCocCount").isMissingNode() && !directTlq.path("upstreamCocCount").isNull()) {
|
|
||||||
directTlqUpstreamCocCount = directTlq.path("upstreamCocCount").asInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
return new PlanContext(
|
return new PlanContext(
|
||||||
firstNonBlank(normalizeUpper(text(root, "productType")), normalizeUpper(task.getProductType())),
|
firstNonBlank(normalizeUpper(text(root, "productType")), normalizeUpper(task.getProductType())),
|
||||||
normalizeUpper(text(request, "orgCodeType")),
|
normalizeUpper(text(request, "orgCodeType")),
|
||||||
@@ -2051,18 +2131,10 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
text(nodes, "node03Ip"),
|
text(nodes, "node03Ip"),
|
||||||
text(nodes, "node04Ip"),
|
text(nodes, "node04Ip"),
|
||||||
text(mq, "tlqLicenseFileId"),
|
text(mq, "tlqLicenseFileId"),
|
||||||
text(mq, "cfmqConfigFileId"),
|
|
||||||
text(licenses, "receiverLicenseFileId"),
|
text(licenses, "receiverLicenseFileId"),
|
||||||
text(licenses, "cfgZipFileId"),
|
text(mq, "cipsGatewayHost"),
|
||||||
text(signServer, "signHost"),
|
text(mq, "cfgZipFileId"),
|
||||||
signPort,
|
text(mq, "cfmqConfigFileId")
|
||||||
text(signServer, "signType"),
|
|
||||||
text(signServer, "signCertDn"),
|
|
||||||
text(signServer, "signCertSn"),
|
|
||||||
text(signServer, "signPassword"),
|
|
||||||
text(directTlq, "localNodeSeq"),
|
|
||||||
text(directTlq, "upstreamInstitutions"),
|
|
||||||
directTlqUpstreamCocCount
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2130,6 +2202,46 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
return "'" + escaped + "'";
|
return "'" + escaped + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Path resolveDirectStageDir(InitTaskEntity task, String relative) {
|
||||||
|
Path stageRoot = Paths.get(firstNonBlank(properties.getStagingRootDir(), "/tmp/tms-init-staging"))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
return stageRoot.resolve(task.getTaskId()).resolve("direct").resolve(relative).normalize().toAbsolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Path resolveTlqGatewaySourceScript(InitTaskEntity task) throws IOException {
|
||||||
|
Path caeTargetDir = Paths.get(firstNonBlank(properties.getDirectCaeTargetDir(), properties.getCfmqTargetDir()))
|
||||||
|
.normalize()
|
||||||
|
.toAbsolutePath();
|
||||||
|
Path preferred = caeTargetDir.resolve("bin").resolve("tlq_gateway.sh").normalize().toAbsolutePath();
|
||||||
|
if (Files.exists(preferred) && Files.isRegularFile(preferred)) {
|
||||||
|
return preferred;
|
||||||
|
}
|
||||||
|
try (Stream<Path> stream = Files.walk(caeTargetDir)) {
|
||||||
|
for (Path item : stream.filter(Files::isRegularFile).toList()) {
|
||||||
|
String name = item.getFileName() == null ? "" : item.getFileName().toString().toLowerCase(Locale.ROOT);
|
||||||
|
if (name.contains("gateway") && name.endsWith(".sh")) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return preferred;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String rewriteGatewayHost(String content, String gatewayHost) {
|
||||||
|
String normalizedHost = normalize(gatewayHost);
|
||||||
|
String rewritten = normalize(content)
|
||||||
|
.replaceAll("(?m)^(\\s*gateway\\s*=\\s*).*$", "$1" + normalizedHost)
|
||||||
|
.replaceAll("(?m)^(\\s*host\\s*=\\s*).*$", "$1" + normalizedHost);
|
||||||
|
if (rewritten.equals(normalize(content))) {
|
||||||
|
rewritten = normalize(content).replace("127.0.0.1", normalizedHost);
|
||||||
|
}
|
||||||
|
if (!rewritten.endsWith(System.lineSeparator())) {
|
||||||
|
rewritten = rewritten + System.lineSeparator();
|
||||||
|
}
|
||||||
|
return rewritten;
|
||||||
|
}
|
||||||
|
|
||||||
private void verifyProcessAbsent(Path logFile, String pattern, String label, List<String> failures) throws IOException {
|
private void verifyProcessAbsent(Path logFile, String pattern, String label, List<String> failures) throws IOException {
|
||||||
try {
|
try {
|
||||||
int code = runCommand(
|
int code = runCommand(
|
||||||
@@ -2249,18 +2361,10 @@ public class ConfigurableInitStepExecutor implements InitStepExecutor {
|
|||||||
String node03Ip,
|
String node03Ip,
|
||||||
String node04Ip,
|
String node04Ip,
|
||||||
String tlqLicenseFileId,
|
String tlqLicenseFileId,
|
||||||
String cfmqConfigFileId,
|
|
||||||
String receiverLicenseFileId,
|
String receiverLicenseFileId,
|
||||||
|
String cipsGatewayHost,
|
||||||
String cfgZipFileId,
|
String cfgZipFileId,
|
||||||
String signHost,
|
String cfmqConfigFileId
|
||||||
Integer signPort,
|
|
||||||
String signType,
|
|
||||||
String signCertDn,
|
|
||||||
String signCertSn,
|
|
||||||
String signPassword,
|
|
||||||
String directTlqLocalNodeSeq,
|
|
||||||
String directTlqUpstreamInstitutions,
|
|
||||||
Integer directTlqUpstreamCocCount
|
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.cisd.tms.modules.init.service.impl;
|
|||||||
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
||||||
import com.cisd.tms.common.enums.ErrorCode;
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
import com.cisd.tms.common.exception.BizException;
|
import com.cisd.tms.common.exception.BizException;
|
||||||
|
import com.cisd.tms.modules.file.repository.FileRecordRepository;
|
||||||
import com.cisd.tms.modules.init.config.InitCommandProfileService;
|
import com.cisd.tms.modules.init.config.InitCommandProfileService;
|
||||||
import com.cisd.tms.modules.init.config.InitExecutorProperties;
|
import com.cisd.tms.modules.init.config.InitExecutorProperties;
|
||||||
import com.cisd.tms.modules.init.dto.InitCreateTaskResponse;
|
import com.cisd.tms.modules.init.dto.InitCreateTaskResponse;
|
||||||
@@ -59,6 +60,7 @@ public class InitServiceImpl implements InitService {
|
|||||||
|
|
||||||
private final InitTaskRepository initTaskRepository;
|
private final InitTaskRepository initTaskRepository;
|
||||||
private final InitTaskStepRepository initTaskStepRepository;
|
private final InitTaskStepRepository initTaskStepRepository;
|
||||||
|
private final FileRecordRepository fileRecordRepository;
|
||||||
private final CisdPresetProperties cisdPresetProperties;
|
private final CisdPresetProperties cisdPresetProperties;
|
||||||
private final ObjectMapper objectMapper;
|
private final ObjectMapper objectMapper;
|
||||||
private final InitStepExecutor initStepExecutor;
|
private final InitStepExecutor initStepExecutor;
|
||||||
@@ -507,9 +509,25 @@ public class InitServiceImpl implements InitService {
|
|||||||
// 该步骤序列只描述“逻辑编排”,具体脚本命令在 step-command-profiles.json 中定义
|
// 该步骤序列只描述“逻辑编排”,具体脚本命令在 step-command-profiles.json 中定义
|
||||||
if ("DIRECT".equals(productType)) {
|
if ("DIRECT".equals(productType)) {
|
||||||
if ("RABBITMQ_CFMQ".equals(mqType)) {
|
if ("RABBITMQ_CFMQ".equals(mqType)) {
|
||||||
return List.of("RENDER_CONFIG", "FILE_PREPARE", "MQ_USER_APPLY", "DB_INIT", "CFMQ_APPLY", "VERIFY");
|
return List.of(
|
||||||
|
"RENDER_CONFIG",
|
||||||
|
"MQ_USER_APPLY",
|
||||||
|
"CFMQ_LINK_APPLY",
|
||||||
|
"CAE_PACKAGE_APPLY",
|
||||||
|
"CFMQ_ROUTE_APPLY",
|
||||||
|
"CAE_UPDATE",
|
||||||
|
"VERIFY"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return List.of("RENDER_CONFIG", "FILE_PREPARE", "MQ_USER_APPLY", "DB_INIT", "TLQ_INIT_CFG", "VERIFY");
|
return List.of(
|
||||||
|
"RENDER_CONFIG",
|
||||||
|
"MQ_USER_APPLY",
|
||||||
|
"CAE_PACKAGE_APPLY",
|
||||||
|
"TLQ_GATEWAY_APPLY",
|
||||||
|
"CAE_UPDATE",
|
||||||
|
"RESTART_TLQ",
|
||||||
|
"VERIFY"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ("ENTERPRISE".equals(productType) && "TLQ".equals(mqType)) {
|
if ("ENTERPRISE".equals(productType) && "TLQ".equals(mqType)) {
|
||||||
return List.of(
|
return List.of(
|
||||||
@@ -621,9 +639,6 @@ public class InitServiceImpl implements InitService {
|
|||||||
if (request.getMq() == null) {
|
if (request.getMq() == null) {
|
||||||
throw new IllegalArgumentException("mq is required");
|
throw new IllegalArgumentException("mq is required");
|
||||||
}
|
}
|
||||||
if (request.getLicenses() == null) {
|
|
||||||
throw new IllegalArgumentException("licenses is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
requireNotBlank("orgCode", request.getOrgCode());
|
requireNotBlank("orgCode", request.getOrgCode());
|
||||||
requireNotBlank("deployMode", request.getDeployMode());
|
requireNotBlank("deployMode", request.getDeployMode());
|
||||||
@@ -631,12 +646,14 @@ public class InitServiceImpl implements InitService {
|
|||||||
requireNotBlank("mq.mqType", request.getMq().getMqType());
|
requireNotBlank("mq.mqType", request.getMq().getMqType());
|
||||||
requireNotBlank("mq.channelUsername", request.getMq().getChannelUsername());
|
requireNotBlank("mq.channelUsername", request.getMq().getChannelUsername());
|
||||||
requireNotBlank("mq.channelPassword", request.getMq().getChannelPassword());
|
requireNotBlank("mq.channelPassword", request.getMq().getChannelPassword());
|
||||||
requireNotBlank("licenses.receiverLicenseFileId", request.getLicenses().getReceiverLicenseFileId());
|
|
||||||
requireFileId("licenses.receiverLicenseFileId", request.getLicenses().getReceiverLicenseFileId());
|
|
||||||
|
|
||||||
|
if (request.getLicenses() != null) {
|
||||||
|
requireOptionalFileId("licenses.receiverLicenseFileId", request.getLicenses().getReceiverLicenseFileId());
|
||||||
|
requireOptionalFileId("licenses.cfgZipFileId", request.getLicenses().getCfgZipFileId());
|
||||||
|
}
|
||||||
requireOptionalFileId("mq.tlqLicenseFileId", request.getMq().getTlqLicenseFileId());
|
requireOptionalFileId("mq.tlqLicenseFileId", request.getMq().getTlqLicenseFileId());
|
||||||
requireOptionalFileId("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
requireOptionalFileId("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
||||||
requireOptionalFileId("licenses.cfgZipFileId", request.getLicenses().getCfgZipFileId());
|
requireOptionalFileId("mq.cfgZipFileId", request.getMq().getCfgZipFileId());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateByProductType(String productType, InitPreviewRequest request) {
|
private void validateByProductType(String productType, InitPreviewRequest request) {
|
||||||
@@ -709,8 +726,8 @@ public class InitServiceImpl implements InitService {
|
|||||||
JsonNode root = objectMapper.readTree(task.getInitPlanJson());
|
JsonNode root = objectMapper.readTree(task.getInitPlanJson());
|
||||||
JsonNode request = root.path("request");
|
JsonNode request = root.path("request");
|
||||||
JsonNode mq = request.path("mq");
|
JsonNode mq = request.path("mq");
|
||||||
|
JsonNode licenses = request.path("licenses");
|
||||||
JsonNode nodes = request.path("nodes");
|
JsonNode nodes = request.path("nodes");
|
||||||
JsonNode directTlq = request.path("directTlq");
|
|
||||||
|
|
||||||
CurrentInitConfigResponse response = new CurrentInitConfigResponse();
|
CurrentInitConfigResponse response = new CurrentInitConfigResponse();
|
||||||
response.setOrgCodeType(firstNonBlank(normalizeUpper(text(request, "orgCodeType")), normalizeUpper(text(root, "orgCodeType"))));
|
response.setOrgCodeType(firstNonBlank(normalizeUpper(text(request, "orgCodeType")), normalizeUpper(text(root, "orgCodeType"))));
|
||||||
@@ -724,12 +741,60 @@ public class InitServiceImpl implements InitService {
|
|||||||
response.setNode01Ip(firstNonBlank(text(nodes, "node01Ip"), text(request, "node01Ip")));
|
response.setNode01Ip(firstNonBlank(text(nodes, "node01Ip"), text(request, "node01Ip")));
|
||||||
response.setNode02Ip(firstNonBlank(text(nodes, "node02Ip"), text(request, "node02Ip")));
|
response.setNode02Ip(firstNonBlank(text(nodes, "node02Ip"), text(request, "node02Ip")));
|
||||||
response.setCipsGatewayHost(firstNonBlank(text(mq, "cipsGatewayHost"), text(request, "cipsGatewayHost")));
|
response.setCipsGatewayHost(firstNonBlank(text(mq, "cipsGatewayHost"), text(request, "cipsGatewayHost")));
|
||||||
|
response.setReceiverLicenseFileName(resolveUploadedFileName(text(licenses, "receiverLicenseFileId")));
|
||||||
|
String mqType = firstNonBlank(normalizeUpper(text(mq, "mqType")), normalizeUpper(text(root, "mqType")), normalizeUpper(task.getMqType()));
|
||||||
|
response.setTlqFileNames(buildTlqFileNames(mq, mqType));
|
||||||
|
response.setCfmqFileNames(buildCfmqFileNames(mq, mqType));
|
||||||
return response;
|
return response;
|
||||||
} catch (JsonProcessingException ex) {
|
} catch (JsonProcessingException ex) {
|
||||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to parse successful init task snapshot");
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "failed to parse successful init task snapshot");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> buildTlqFileNames(
|
||||||
|
JsonNode mq,
|
||||||
|
String mqType
|
||||||
|
) {
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
if (!Set.of("TLQ", "RABBITMQ_TLQ").contains(normalizeUpper(mqType))) {
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
addUploadedFileName(fileNames, text(mq, "tlqLicenseFileId"));
|
||||||
|
addUploadedFileName(fileNames, text(mq, "cfgZipFileId"));
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<String> buildCfmqFileNames(
|
||||||
|
JsonNode mq,
|
||||||
|
String mqType
|
||||||
|
) {
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
if (!"RABBITMQ_CFMQ".equals(normalizeUpper(mqType))) {
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
addUploadedFileName(fileNames, text(mq, "cfgZipFileId"));
|
||||||
|
addUploadedFileName(fileNames, text(mq, "cfmqConfigFileId"));
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addUploadedFileName(List<String> fileNames, String fileId) {
|
||||||
|
String fileName = resolveUploadedFileName(fileId);
|
||||||
|
if (isBlank(fileName)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileNames.add(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String resolveUploadedFileName(String fileId) {
|
||||||
|
if (isBlank(fileId)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fileRecordRepository.findByFileId(normalize(fileId))
|
||||||
|
.map(record -> normalize(record.getOriginalFilename()))
|
||||||
|
.filter(name -> !name.isEmpty())
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
private int compareTaskRecency(InitTaskEntity left, InitTaskEntity right) {
|
private int compareTaskRecency(InitTaskEntity left, InitTaskEntity right) {
|
||||||
Comparator<LocalDateTime> comparator = Comparator.nullsFirst(LocalDateTime::compareTo);
|
Comparator<LocalDateTime> comparator = Comparator.nullsFirst(LocalDateTime::compareTo);
|
||||||
int byUpdate = comparator.compare(left.getUpdateTime(), right.getUpdateTime());
|
int byUpdate = comparator.compare(left.getUpdateTime(), right.getUpdateTime());
|
||||||
@@ -746,6 +811,11 @@ public class InitServiceImpl implements InitService {
|
|||||||
private void validateStandard(String productType, InitPreviewRequest request, String deployMode, String mqType) {
|
private void validateStandard(String productType, InitPreviewRequest request, String deployMode, String mqType) {
|
||||||
requireAllowed("deployMode", deployMode, DEPLOY_STANDARD);
|
requireAllowed("deployMode", deployMode, DEPLOY_STANDARD);
|
||||||
requireAllowed("mq.mqType", mqType, resolveStandardMqAllowed(productType));
|
requireAllowed("mq.mqType", mqType, resolveStandardMqAllowed(productType));
|
||||||
|
if (request.getLicenses() == null) {
|
||||||
|
throw new IllegalArgumentException("licenses is required");
|
||||||
|
}
|
||||||
|
requireNotBlank("licenses.receiverLicenseFileId", request.getLicenses().getReceiverLicenseFileId());
|
||||||
|
requireFileId("licenses.receiverLicenseFileId", request.getLicenses().getReceiverLicenseFileId());
|
||||||
|
|
||||||
if ("DUAL".equals(deployMode)) {
|
if ("DUAL".equals(deployMode)) {
|
||||||
requireNotBlank("nodes.node02Ip", request.getNodes().getNode02Ip());
|
requireNotBlank("nodes.node02Ip", request.getNodes().getNode02Ip());
|
||||||
@@ -779,26 +849,14 @@ public class InitServiceImpl implements InitService {
|
|||||||
requireNotBlank("nodes.node04Ip", request.getNodes().getNode04Ip());
|
requireNotBlank("nodes.node04Ip", request.getNodes().getNode04Ip());
|
||||||
}
|
}
|
||||||
|
|
||||||
requireNotBlank("licenses.cfgZipFileId", request.getLicenses().getCfgZipFileId());
|
|
||||||
requireFileId("licenses.cfgZipFileId", request.getLicenses().getCfgZipFileId());
|
|
||||||
|
|
||||||
if ("RABBITMQ_TLQ".equals(mqType)) {
|
if ("RABBITMQ_TLQ".equals(mqType)) {
|
||||||
requireNotBlank("mq.tlqLicenseFileId", request.getMq().getTlqLicenseFileId());
|
requireNotBlank("mq.cfgZipFileId", request.getMq().getCfgZipFileId());
|
||||||
requireFileId("mq.tlqLicenseFileId", request.getMq().getTlqLicenseFileId());
|
requireFileId("mq.cfgZipFileId", request.getMq().getCfgZipFileId());
|
||||||
InitPreviewRequest.DirectTlqConfig directTlq = request.getDirectTlq();
|
|
||||||
if (directTlq == null) {
|
|
||||||
throw new IllegalArgumentException("directTlq is required for RABBITMQ_TLQ");
|
|
||||||
}
|
|
||||||
requireNotBlank("directTlq.localNodeSeq", directTlq.getLocalNodeSeq());
|
|
||||||
requireNotBlank("directTlq.upstreamInstitutions", directTlq.getUpstreamInstitutions());
|
|
||||||
requireNotBlank("mq.cipsGatewayHost", request.getMq().getCipsGatewayHost());
|
requireNotBlank("mq.cipsGatewayHost", request.getMq().getCipsGatewayHost());
|
||||||
if (directTlq.getUpstreamCocCount() == null
|
|
||||||
|| directTlq.getUpstreamCocCount() < 1
|
|
||||||
|| directTlq.getUpstreamCocCount() > 2) {
|
|
||||||
throw new IllegalArgumentException("directTlq.upstreamCocCount must be in [1,2]");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ("RABBITMQ_CFMQ".equals(mqType)) {
|
if ("RABBITMQ_CFMQ".equals(mqType)) {
|
||||||
|
requireNotBlank("mq.cfgZipFileId", request.getMq().getCfgZipFileId());
|
||||||
|
requireFileId("mq.cfgZipFileId", request.getMq().getCfgZipFileId());
|
||||||
requireNotBlank("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
requireNotBlank("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
||||||
requireFileId("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
requireFileId("mq.cfmqConfigFileId", request.getMq().getCfmqConfigFileId());
|
||||||
}
|
}
|
||||||
@@ -859,6 +917,7 @@ public class InitServiceImpl implements InitService {
|
|||||||
return normalize(child.toString());
|
return normalize(child.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static String normalizeUpper(String value) {
|
private static String normalizeUpper(String value) {
|
||||||
return normalize(value).toUpperCase(Locale.ROOT);
|
return normalize(value).toUpperCase(Locale.ROOT);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,14 +73,16 @@ public class UpgradeController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/upgrades")
|
@GetMapping("/upgrades")
|
||||||
@Operation(summary = "查询升级记录列表", description = "分页查询升级任务列表,支持按升级对象和状态筛选。")
|
@Operation(summary = "查询升级记录列表", description = "分页查询升级任务列表,支持按升级对象、状态和升级日期筛选。")
|
||||||
public ApiResponse<UpgradeTaskPageResponse> list(
|
public ApiResponse<UpgradeTaskPageResponse> list(
|
||||||
@RequestParam(defaultValue = "1") int page,
|
@RequestParam(defaultValue = "1") int page,
|
||||||
@RequestParam(defaultValue = "10") int pageSize,
|
@RequestParam(defaultValue = "10") int pageSize,
|
||||||
@RequestParam(required = false) String taskType,
|
@RequestParam(required = false) String taskType,
|
||||||
@RequestParam(required = false) String status
|
@RequestParam(required = false) String status,
|
||||||
|
@Parameter(description = "升级日期,格式 yyyy-MM-dd,按 startedAt 所在自然日筛选")
|
||||||
|
@RequestParam(required = false) String upgradeDate
|
||||||
) {
|
) {
|
||||||
return ApiResponse.success(upgradeService.listTasks(page, pageSize, taskType, status));
|
return ApiResponse.success(upgradeService.listTasks(page, pageSize, taskType, status, upgradeDate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/upgrades/{taskId}")
|
@GetMapping("/upgrades/{taskId}")
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ public class UpgradeCreateTaskRequest {
|
|||||||
|
|
||||||
@Schema(description = "升级包文件标识", example = "FILE-20260319-000001", requiredMode = Schema.RequiredMode.REQUIRED)
|
@Schema(description = "升级包文件标识", example = "FILE-20260319-000001", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
private String fileId;
|
private String fileId;
|
||||||
|
@Schema(description = "用户选择的升级任务类型,必须与升级包解析结果一致", example = "TMS", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||||
|
private String taskType;
|
||||||
|
|
||||||
public String getFileId() {
|
public String getFileId() {
|
||||||
return fileId;
|
return fileId;
|
||||||
@@ -15,4 +17,12 @@ public class UpgradeCreateTaskRequest {
|
|||||||
public void setFileId(String fileId) {
|
public void setFileId(String fileId) {
|
||||||
this.fileId = fileId;
|
this.fileId = fileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getTaskType() {
|
||||||
|
return taskType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTaskType(String taskType) {
|
||||||
|
this.taskType = taskType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,13 +17,17 @@ public interface UpgradeTaskMapper extends BaseMapperX<UpgradeTaskEntity> {
|
|||||||
List<UpgradeTaskEntity> selectPage(
|
List<UpgradeTaskEntity> selectPage(
|
||||||
@Param("taskType") String taskType,
|
@Param("taskType") String taskType,
|
||||||
@Param("status") String status,
|
@Param("status") String status,
|
||||||
|
@Param("startedAtBegin") LocalDateTime startedAtBegin,
|
||||||
|
@Param("startedAtEndExclusive") LocalDateTime startedAtEndExclusive,
|
||||||
@Param("offset") int offset,
|
@Param("offset") int offset,
|
||||||
@Param("limit") int limit
|
@Param("limit") int limit
|
||||||
);
|
);
|
||||||
|
|
||||||
long countPage(
|
long countPage(
|
||||||
@Param("taskType") String taskType,
|
@Param("taskType") String taskType,
|
||||||
@Param("status") String status
|
@Param("status") String status,
|
||||||
|
@Param("startedAtBegin") LocalDateTime startedAtBegin,
|
||||||
|
@Param("startedAtEndExclusive") LocalDateTime startedAtEndExclusive
|
||||||
);
|
);
|
||||||
|
|
||||||
int updateStatusByTaskId(
|
int updateStatusByTaskId(
|
||||||
|
|||||||
@@ -13,9 +13,16 @@ public interface UpgradeTaskRepository {
|
|||||||
|
|
||||||
Optional<UpgradeTaskEntity> findRunningTask();
|
Optional<UpgradeTaskEntity> findRunningTask();
|
||||||
|
|
||||||
List<UpgradeTaskEntity> findPage(String taskType, String status, int offset, int limit);
|
List<UpgradeTaskEntity> findPage(
|
||||||
|
String taskType,
|
||||||
|
String status,
|
||||||
|
LocalDateTime startedAtBegin,
|
||||||
|
LocalDateTime startedAtEndExclusive,
|
||||||
|
int offset,
|
||||||
|
int limit
|
||||||
|
);
|
||||||
|
|
||||||
long countPage(String taskType, String status);
|
long countPage(String taskType, String status, LocalDateTime startedAtBegin, LocalDateTime startedAtEndExclusive);
|
||||||
|
|
||||||
void updateStatus(
|
void updateStatus(
|
||||||
String taskId,
|
String taskId,
|
||||||
|
|||||||
+11
-4
@@ -33,13 +33,20 @@ public class UpgradeTaskRepositoryImpl implements UpgradeTaskRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UpgradeTaskEntity> findPage(String taskType, String status, int offset, int limit) {
|
public List<UpgradeTaskEntity> findPage(
|
||||||
return upgradeTaskMapper.selectPage(taskType, status, offset, limit);
|
String taskType,
|
||||||
|
String status,
|
||||||
|
LocalDateTime startedAtBegin,
|
||||||
|
LocalDateTime startedAtEndExclusive,
|
||||||
|
int offset,
|
||||||
|
int limit
|
||||||
|
) {
|
||||||
|
return upgradeTaskMapper.selectPage(taskType, status, startedAtBegin, startedAtEndExclusive, offset, limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long countPage(String taskType, String status) {
|
public long countPage(String taskType, String status, LocalDateTime startedAtBegin, LocalDateTime startedAtEndExclusive) {
|
||||||
return upgradeTaskMapper.countPage(taskType, status);
|
return upgradeTaskMapper.countPage(taskType, status, startedAtBegin, startedAtEndExclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -19,8 +19,10 @@ import com.cisd.tms.modules.upgrade.repository.UpgradeTaskRepository;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.DateTimeParseException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
@@ -36,6 +38,7 @@ import org.springframework.stereotype.Service;
|
|||||||
public class UpgradeService {
|
public class UpgradeService {
|
||||||
|
|
||||||
private static final DateTimeFormatter TASK_ID_TS = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
private static final DateTimeFormatter TASK_ID_TS = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
|
||||||
|
private static final DateTimeFormatter UPGRADE_DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||||
|
|
||||||
private final UpgradeTaskRepository upgradeTaskRepository;
|
private final UpgradeTaskRepository upgradeTaskRepository;
|
||||||
private final FileRecordRepository fileRecordRepository;
|
private final FileRecordRepository fileRecordRepository;
|
||||||
@@ -97,11 +100,17 @@ public class UpgradeService {
|
|||||||
if (request == null || request.getFileId() == null || request.getFileId().isBlank()) {
|
if (request == null || request.getFileId() == null || request.getFileId().isBlank()) {
|
||||||
throw new IllegalArgumentException("fileId must not be blank");
|
throw new IllegalArgumentException("fileId must not be blank");
|
||||||
}
|
}
|
||||||
|
if (request.getTaskType() == null || request.getTaskType().isBlank()) {
|
||||||
|
throw new IllegalArgumentException("taskType must not be blank");
|
||||||
|
}
|
||||||
// 创建任务前重新预检一次,避免用户上传后替换文件或设备版本状态发生变化。
|
// 创建任务前重新预检一次,避免用户上传后替换文件或设备版本状态发生变化。
|
||||||
UpgradePreviewResponse preview = upgradePackageService.preview(request.getFileId());
|
UpgradePreviewResponse preview = upgradePackageService.preview(request.getFileId());
|
||||||
if (!preview.isAllowed()) {
|
if (!preview.isAllowed()) {
|
||||||
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), blankAs(preview.getBlockReason(), "upgrade preview not allowed"));
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), blankAs(preview.getBlockReason(), "upgrade preview not allowed"));
|
||||||
}
|
}
|
||||||
|
if (!trim(request.getTaskType()).equals(trim(preview.getTaskType()))) {
|
||||||
|
throw new BizException(ErrorCode.BIZ_ERROR.getCode(), "selected taskType does not match package taskType");
|
||||||
|
}
|
||||||
FileRecordEntity fileRecord = fileRecordRepository.findByFileId(request.getFileId().trim())
|
FileRecordEntity fileRecord = fileRecordRepository.findByFileId(request.getFileId().trim())
|
||||||
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade package file not found: " + request.getFileId().trim()));
|
.orElseThrow(() -> new BizException(ErrorCode.BIZ_ERROR.getCode(), "upgrade package file not found: " + request.getFileId().trim()));
|
||||||
|
|
||||||
@@ -186,12 +195,27 @@ public class UpgradeService {
|
|||||||
return toResponse(loadTask(taskId));
|
return toResponse(loadTask(taskId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public UpgradeTaskPageResponse listTasks(int page, int pageSize, String taskType, String status) {
|
public UpgradeTaskPageResponse listTasks(int page, int pageSize, String taskType, String status, String upgradeDate) {
|
||||||
int normalizedPage = Math.max(1, page);
|
int normalizedPage = Math.max(1, page);
|
||||||
int normalizedPageSize = Math.max(1, pageSize);
|
int normalizedPageSize = Math.max(1, pageSize);
|
||||||
int offset = (normalizedPage - 1) * normalizedPageSize;
|
int offset = (normalizedPage - 1) * normalizedPageSize;
|
||||||
List<UpgradeTaskEntity> entities = upgradeTaskRepository.findPage(trim(taskType), trim(status), offset, normalizedPageSize);
|
LocalDateTime startedAtBegin = null;
|
||||||
long total = upgradeTaskRepository.countPage(trim(taskType), trim(status));
|
LocalDateTime startedAtEndExclusive = null;
|
||||||
|
String normalizedUpgradeDate = trim(upgradeDate);
|
||||||
|
if (!normalizedUpgradeDate.isEmpty()) {
|
||||||
|
LocalDate filterDate = parseUpgradeDate(normalizedUpgradeDate);
|
||||||
|
startedAtBegin = filterDate.atStartOfDay();
|
||||||
|
startedAtEndExclusive = filterDate.plusDays(1).atStartOfDay();
|
||||||
|
}
|
||||||
|
List<UpgradeTaskEntity> entities = upgradeTaskRepository.findPage(
|
||||||
|
trim(taskType),
|
||||||
|
trim(status),
|
||||||
|
startedAtBegin,
|
||||||
|
startedAtEndExclusive,
|
||||||
|
offset,
|
||||||
|
normalizedPageSize
|
||||||
|
);
|
||||||
|
long total = upgradeTaskRepository.countPage(trim(taskType), trim(status), startedAtBegin, startedAtEndExclusive);
|
||||||
|
|
||||||
UpgradeTaskPageResponse response = new UpgradeTaskPageResponse();
|
UpgradeTaskPageResponse response = new UpgradeTaskPageResponse();
|
||||||
response.setPage(normalizedPage);
|
response.setPage(normalizedPage);
|
||||||
@@ -267,4 +291,12 @@ public class UpgradeService {
|
|||||||
private String blankAs(String value, String fallback) {
|
private String blankAs(String value, String fallback) {
|
||||||
return trim(value).isEmpty() ? fallback : trim(value);
|
return trim(value).isEmpty() ? fallback : trim(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private LocalDate parseUpgradeDate(String upgradeDate) {
|
||||||
|
try {
|
||||||
|
return LocalDate.parse(upgradeDate, UPGRADE_DATE_FORMAT);
|
||||||
|
} catch (DateTimeParseException ex) {
|
||||||
|
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), "upgradeDate must be yyyy-MM-dd");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,12 @@
|
|||||||
<if test="status != null and status != ''">
|
<if test="status != null and status != ''">
|
||||||
AND status = #{status}
|
AND status = #{status}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="startedAtBegin != null">
|
||||||
|
AND started_at <![CDATA[ >= ]]> #{startedAtBegin}
|
||||||
|
</if>
|
||||||
|
<if test="startedAtEndExclusive != null">
|
||||||
|
AND started_at <![CDATA[ < ]]> #{startedAtEndExclusive}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
ORDER BY create_time DESC, id DESC
|
ORDER BY create_time DESC, id DESC
|
||||||
LIMIT #{limit} OFFSET #{offset}
|
LIMIT #{limit} OFFSET #{offset}
|
||||||
@@ -74,6 +80,12 @@
|
|||||||
<if test="status != null and status != ''">
|
<if test="status != null and status != ''">
|
||||||
AND status = #{status}
|
AND status = #{status}
|
||||||
</if>
|
</if>
|
||||||
|
<if test="startedAtBegin != null">
|
||||||
|
AND started_at <![CDATA[ >= ]]> #{startedAtBegin}
|
||||||
|
</if>
|
||||||
|
<if test="startedAtEndExclusive != null">
|
||||||
|
AND started_at <![CDATA[ < ]]> #{startedAtEndExclusive}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.cisd.tms.modules.device.service;
|
|||||||
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.service.MockPcieCryptoService;
|
import com.cisd.tms.integration.crypto.pcie.service.MockPcieCryptoService;
|
||||||
|
import com.cisd.tms.modules.file.entity.FileRecordEntity;
|
||||||
|
import com.cisd.tms.modules.file.repository.FileRecordRepository;
|
||||||
import com.cisd.tms.modules.device.config.DeviceProfileProperties;
|
import com.cisd.tms.modules.device.config.DeviceProfileProperties;
|
||||||
import com.cisd.tms.modules.device.dto.DeviceProfileResponse;
|
import com.cisd.tms.modules.device.dto.DeviceProfileResponse;
|
||||||
import com.cisd.tms.modules.device.dto.DeviceProfileSoftwareItem;
|
import com.cisd.tms.modules.device.dto.DeviceProfileSoftwareItem;
|
||||||
@@ -313,6 +315,7 @@ class DeviceProfileServiceTest {
|
|||||||
return new InitServiceImpl(
|
return new InitServiceImpl(
|
||||||
new InMemoryInitTaskRepository(),
|
new InMemoryInitTaskRepository(),
|
||||||
new InMemoryInitTaskStepRepository(),
|
new InMemoryInitTaskStepRepository(),
|
||||||
|
emptyFileRecordRepository(),
|
||||||
preset(productType),
|
preset(productType),
|
||||||
objectMapper,
|
objectMapper,
|
||||||
successExecutor(),
|
successExecutor(),
|
||||||
@@ -329,6 +332,19 @@ class DeviceProfileServiceTest {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FileRecordRepository emptyFileRecordRepository() {
|
||||||
|
return new FileRecordRepository() {
|
||||||
|
@Override
|
||||||
|
public Optional<FileRecordEntity> findByFileId(String fileId) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(FileRecordEntity entity) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static InitStepExecutor successExecutor() {
|
private static InitStepExecutor successExecutor() {
|
||||||
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.cisd.tms.modules.device.service;
|
|||||||
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.service.MockPcieCryptoService;
|
import com.cisd.tms.integration.crypto.pcie.service.MockPcieCryptoService;
|
||||||
|
import com.cisd.tms.modules.file.entity.FileRecordEntity;
|
||||||
|
import com.cisd.tms.modules.file.repository.FileRecordRepository;
|
||||||
import com.cisd.tms.modules.device.dto.DeviceRuntimeStatusResponse;
|
import com.cisd.tms.modules.device.dto.DeviceRuntimeStatusResponse;
|
||||||
import com.cisd.tms.modules.device.dto.SoftwareRuntimeStatusItem;
|
import com.cisd.tms.modules.device.dto.SoftwareRuntimeStatusItem;
|
||||||
import com.cisd.tms.modules.device.entity.DeviceSoftwareVersionEntity;
|
import com.cisd.tms.modules.device.entity.DeviceSoftwareVersionEntity;
|
||||||
@@ -146,6 +148,31 @@ class DeviceRuntimeStatusServiceTest {
|
|||||||
assertSoftwareAbsent(response.getSoftware(), "TLQ");
|
assertSoftwareAbsent(response.getSoftware(), "TLQ");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUseCurrentInitProductTypeBeforePresetWhenChoosingReceiverProbe() {
|
||||||
|
InitService initService = newInitService("DIRECT");
|
||||||
|
createSuccessfulInitTask(initService, validDirectInitRequest("RABBITMQ_TLQ"));
|
||||||
|
InMemoryDeviceSoftwareVersionRepository versions = new InMemoryDeviceSoftwareVersionRepository();
|
||||||
|
versions.save(component("RECEIVER", "直参轻量化终端版", "V1.3.2"));
|
||||||
|
|
||||||
|
DeviceRuntimeStatusService service = new DeviceRuntimeStatusServiceImpl(
|
||||||
|
initService,
|
||||||
|
cryptoService(),
|
||||||
|
hardwareProbe(10.0, 8.0, 16.0, 100.0, 256.0),
|
||||||
|
softwareVersionProbe("SYD TMS V1.00"),
|
||||||
|
softwareRuntimeProbe(Map.of(
|
||||||
|
"APP_STANDARD", false,
|
||||||
|
"APP_DIRECT", true
|
||||||
|
)),
|
||||||
|
versions,
|
||||||
|
preset("ENTERPRISE")
|
||||||
|
);
|
||||||
|
|
||||||
|
DeviceRuntimeStatusResponse response = service.loadRuntimeStatus();
|
||||||
|
|
||||||
|
assertSoftwareStatus(response.getSoftware(), "RECEIVER", "NORMAL");
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertSoftwareStatus(List<SoftwareRuntimeStatusItem> items, String code, String expectedStatus) {
|
private static void assertSoftwareStatus(List<SoftwareRuntimeStatusItem> items, String code, String expectedStatus) {
|
||||||
SoftwareRuntimeStatusItem item = items.stream()
|
SoftwareRuntimeStatusItem item = items.stream()
|
||||||
.filter(candidate -> code.equals(candidate.getComponentCode()))
|
.filter(candidate -> code.equals(candidate.getComponentCode()))
|
||||||
@@ -358,6 +385,7 @@ class DeviceRuntimeStatusServiceTest {
|
|||||||
return new InitServiceImpl(
|
return new InitServiceImpl(
|
||||||
new InMemoryInitTaskRepository(),
|
new InMemoryInitTaskRepository(),
|
||||||
new InMemoryInitTaskStepRepository(),
|
new InMemoryInitTaskStepRepository(),
|
||||||
|
emptyFileRecordRepository(),
|
||||||
preset(productType),
|
preset(productType),
|
||||||
objectMapper,
|
objectMapper,
|
||||||
successExecutor(),
|
successExecutor(),
|
||||||
@@ -374,6 +402,19 @@ class DeviceRuntimeStatusServiceTest {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FileRecordRepository emptyFileRecordRepository() {
|
||||||
|
return new FileRecordRepository() {
|
||||||
|
@Override
|
||||||
|
public Optional<FileRecordEntity> findByFileId(String fileId) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(FileRecordEntity entity) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static InitStepExecutor successExecutor() {
|
private static InitStepExecutor successExecutor() {
|
||||||
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
||||||
}
|
}
|
||||||
@@ -405,6 +446,19 @@ class DeviceRuntimeStatusServiceTest {
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static InitPreviewRequest validDirectInitRequest(String mqType) {
|
||||||
|
InitPreviewRequest request = validInitRequest(mqType);
|
||||||
|
InitPreviewRequest.Mq mq = request.getMq();
|
||||||
|
mq.setCfgZipFileId("file-direct-cfg-001");
|
||||||
|
if ("RABBITMQ_TLQ".equals(mqType)) {
|
||||||
|
mq.setCipsGatewayHost("192.168.10.20");
|
||||||
|
}
|
||||||
|
if ("RABBITMQ_CFMQ".equals(mqType)) {
|
||||||
|
mq.setCfmqConfigFileId("file-direct-cfmq-001");
|
||||||
|
}
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
private static void createSuccessfulInitTask(InitService service, InitPreviewRequest request) {
|
private static void createSuccessfulInitTask(InitService service, InitPreviewRequest request) {
|
||||||
InitCreateTaskResponse created = service.createTask(request);
|
InitCreateTaskResponse created = service.createTask(request);
|
||||||
service.executeTask(created.getTaskId());
|
service.executeTask(created.getTaskId());
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
|||||||
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
import com.cisd.tms.integration.crypto.pcie.model.DeviceInfoResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult;
|
import com.cisd.tms.integration.crypto.pcie.model.DeviceStatusResult;
|
||||||
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
import com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService;
|
||||||
|
import com.cisd.tms.modules.file.entity.FileRecordEntity;
|
||||||
|
import com.cisd.tms.modules.file.repository.FileRecordRepository;
|
||||||
import com.cisd.tms.modules.device.config.DeviceProfileProperties;
|
import com.cisd.tms.modules.device.config.DeviceProfileProperties;
|
||||||
import com.cisd.tms.modules.device.dto.DeviceInfoResponse;
|
import com.cisd.tms.modules.device.dto.DeviceInfoResponse;
|
||||||
import com.cisd.tms.modules.device.entity.DeviceSoftwareVersionEntity;
|
import com.cisd.tms.modules.device.entity.DeviceSoftwareVersionEntity;
|
||||||
@@ -100,6 +102,7 @@ class DeviceServiceTest {
|
|||||||
return new InitServiceImpl(
|
return new InitServiceImpl(
|
||||||
taskRepository,
|
taskRepository,
|
||||||
stepRepository,
|
stepRepository,
|
||||||
|
emptyFileRecordRepository(),
|
||||||
preset(productType),
|
preset(productType),
|
||||||
objectMapper,
|
objectMapper,
|
||||||
successExecutor(),
|
successExecutor(),
|
||||||
@@ -116,6 +119,19 @@ class DeviceServiceTest {
|
|||||||
return properties;
|
return properties;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FileRecordRepository emptyFileRecordRepository() {
|
||||||
|
return new FileRecordRepository() {
|
||||||
|
@Override
|
||||||
|
public Optional<FileRecordEntity> findByFileId(String fileId) {
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(FileRecordEntity entity) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private static InitStepExecutor successExecutor() {
|
private static InitStepExecutor successExecutor() {
|
||||||
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
return (task, step) -> InitStepExecutionResult.success("ok", 0, null);
|
||||||
}
|
}
|
||||||
|
|||||||
+57
@@ -66,4 +66,61 @@ class DefaultSoftwareRuntimeProbeTest {
|
|||||||
|
|
||||||
Assertions.assertFalse(probe.isStandardAppRunning());
|
Assertions.assertFalse(probe.isStandardAppRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldTreatRabbitmqAsRunningWhenRabbitmqctlSucceedsWithoutProcessNameMatch() {
|
||||||
|
DefaultSoftwareRuntimeProbe probe = new DefaultSoftwareRuntimeProbe(
|
||||||
|
List::of,
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
System::nanoTime,
|
||||||
|
command -> String.join(" ", command).contains("rabbitmqctl status") ? 0 : 1
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertTrue(probe.isRabbitmqRunning());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldTreatStandardReceiverAsRunningForUppercaseJarProcesses() {
|
||||||
|
DefaultSoftwareRuntimeProbe probe = new DefaultSoftwareRuntimeProbe(
|
||||||
|
() -> List.of(
|
||||||
|
"java -jar /home/cmep4i/cmsp/CMEP-CMSP-INDIRECT.jar",
|
||||||
|
"java -jar /home/cmep4i/cmtp/CMEP-CMTP.jar"
|
||||||
|
),
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
System::nanoTime
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertTrue(probe.isStandardAppRunning());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldNotTreatCmtp4caeAsStandardCmtpProcess() {
|
||||||
|
DefaultSoftwareRuntimeProbe probe = new DefaultSoftwareRuntimeProbe(
|
||||||
|
() -> List.of(
|
||||||
|
"/home/cmep4d/cmsp/start_cmsp.sh",
|
||||||
|
"/home/cmep4d/cmtp4cae/bin/startup.sh"
|
||||||
|
),
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
System::nanoTime
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertFalse(probe.isStandardAppRunning());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldTreatDirectReceiverAsRunningWhenAllManualServicesAreAlive() {
|
||||||
|
DefaultSoftwareRuntimeProbe probe = new DefaultSoftwareRuntimeProbe(
|
||||||
|
() -> List.of(
|
||||||
|
"pmtsstat start cold",
|
||||||
|
"cmcp daemon",
|
||||||
|
"java -jar CMEP-CMSP-INDIRECT.jar",
|
||||||
|
"java -jar CMEP-CMTP.jar",
|
||||||
|
"cmtp4cae worker"
|
||||||
|
),
|
||||||
|
Duration.ofSeconds(1),
|
||||||
|
System::nanoTime
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertTrue(probe.isDirectAppRunning());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+153
-99
@@ -74,22 +74,17 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRenderDirectCpconfigFromUploadBaseDir() throws IOException {
|
void shouldRenderDirectCpconfigWithoutSignServerInput() throws IOException {
|
||||||
Path tempRoot = Files.createTempDirectory("init-executor-render-fileid-test");
|
Path tempRoot = Files.createTempDirectory("init-executor-render-fileid-test");
|
||||||
Path uploadDir = tempRoot.resolve("uploads");
|
Path uploadDir = tempRoot.resolve("uploads");
|
||||||
Path cfgDir = uploadDir.resolve("65");
|
Files.createDirectories(uploadDir);
|
||||||
Files.createDirectories(cfgDir);
|
Path cpconfig = tempRoot.resolve("cpconfig.cfg");
|
||||||
Path cpconfig = cfgDir.resolve("cpconfig.cfg");
|
|
||||||
Files.writeString(cpconfig, """
|
Files.writeString(cpconfig, """
|
||||||
MY_CIPSID_OR_BIC=OLD
|
MY_CIPSID_OR_BIC=OLD
|
||||||
MQ_TYPE=1
|
MQ_TYPE=1
|
||||||
node_01_ip=127.0.0.1
|
node_01_ip=127.0.0.1
|
||||||
db_ip=127.0.0.1
|
db_ip=127.0.0.1
|
||||||
sign_host=127.0.0.1
|
db_port=4000
|
||||||
sign_port=50006
|
|
||||||
sign_type=Infosec
|
|
||||||
sign_cert_dn='old'
|
|
||||||
sign_cert_sn=old
|
|
||||||
""");
|
""");
|
||||||
|
|
||||||
InitExecutorProperties properties = new InitExecutorProperties();
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
@@ -97,6 +92,7 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
properties.setLogDir(tempRoot.resolve("logs").toString());
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
properties.setUploadBaseDir(uploadDir.toString());
|
properties.setUploadBaseDir(uploadDir.toString());
|
||||||
properties.setDirectCpconfigFileName("cpconfig.cfg");
|
properties.setDirectCpconfigFileName("cpconfig.cfg");
|
||||||
|
properties.setDirectCpconfigTargetPath(cpconfig.toString());
|
||||||
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
InitTaskEntity task = new InitTaskEntity();
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
@@ -111,21 +107,7 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
"orgNameEn", "TEST BANK",
|
"orgNameEn", "TEST BANK",
|
||||||
"deployMode", "SINGLE",
|
"deployMode", "SINGLE",
|
||||||
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
||||||
"mq", Map.of("mqType", "RABBITMQ_TLQ", "tlqLicenseFileId", "file-tlq-001"),
|
"mq", Map.of("mqType", "RABBITMQ_TLQ", "cipsGatewayHost", "172.30.1.10", "cfgZipFileId", "cae-001")
|
||||||
"licenses", Map.of("cfgZipFileId", "65"),
|
|
||||||
"signServer", Map.of(
|
|
||||||
"signHost", "172.30.1.101",
|
|
||||||
"signPort", 50006,
|
|
||||||
"signType", "Infosec",
|
|
||||||
"signCertDn", "CN=TEST,OU=CIPS",
|
|
||||||
"signCertSn", "123456",
|
|
||||||
"signPassword", "secret"
|
|
||||||
),
|
|
||||||
"directTlq", Map.of(
|
|
||||||
"localNodeSeq", "A",
|
|
||||||
"upstreamInstitutions", "CIPSCNSHXXX",
|
|
||||||
"upstreamCocCount", 1
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
@@ -140,15 +122,15 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
String rendered = Files.readString(renderedPath);
|
String rendered = Files.readString(renderedPath);
|
||||||
Assertions.assertTrue(rendered.contains("MY_CIPSID_OR_BIC=AAAABBBBXXX"));
|
Assertions.assertTrue(rendered.contains("MY_CIPSID_OR_BIC=AAAABBBBXXX"));
|
||||||
Assertions.assertTrue(rendered.contains("node_01_ip=10.0.1.1"));
|
Assertions.assertTrue(rendered.contains("node_01_ip=10.0.1.1"));
|
||||||
|
Assertions.assertTrue(rendered.contains("db_ip=127.0.0.1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRenderDirectCpconfigFromCfgDirectory() throws IOException {
|
void shouldVerifyDirectConfigWithoutSignFields() throws IOException {
|
||||||
Path tempRoot = Files.createTempDirectory("init-executor-render-test");
|
Path tempRoot = Files.createTempDirectory("init-executor-render-test");
|
||||||
Path uploadDir = tempRoot.resolve("uploads");
|
Path uploadDir = tempRoot.resolve("uploads");
|
||||||
Path cfgDir = uploadDir.resolve("cfg-001");
|
Files.createDirectories(uploadDir);
|
||||||
Files.createDirectories(cfgDir);
|
Path cpconfig = tempRoot.resolve("cpconfig.cfg");
|
||||||
Path cpconfig = cfgDir.resolve("cpconfig.cfg");
|
|
||||||
Files.writeString(cpconfig, """
|
Files.writeString(cpconfig, """
|
||||||
MY_CIPSID_OR_BIC=OLD
|
MY_CIPSID_OR_BIC=OLD
|
||||||
MQ_TYPE=1
|
MQ_TYPE=1
|
||||||
@@ -159,23 +141,18 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
node_03_ip=127.0.0.1
|
node_03_ip=127.0.0.1
|
||||||
node_04_ip=127.0.0.1
|
node_04_ip=127.0.0.1
|
||||||
db_ip=127.0.0.1
|
db_ip=127.0.0.1
|
||||||
sign_host=127.0.0.1
|
db_port=4000
|
||||||
sign_port=50006
|
|
||||||
sign_password=old
|
|
||||||
sign_type=Infosec
|
|
||||||
sign_cert_dn='old'
|
|
||||||
sign_cert_sn=old
|
|
||||||
MY_BIC_CODE=OLD
|
MY_BIC_CODE=OLD
|
||||||
MY_CIPS_ID=
|
MY_CIPS_ID=
|
||||||
MY_LEI_CODE=
|
MY_LEI_CODE=
|
||||||
""");
|
""");
|
||||||
Files.writeString(uploadDir.resolve("cfmq-001"), "cfmq.host=127.0.0.1");
|
|
||||||
|
|
||||||
InitExecutorProperties properties = new InitExecutorProperties();
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
||||||
properties.setLogDir(tempRoot.resolve("logs").toString());
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
properties.setUploadBaseDir(uploadDir.toString());
|
properties.setUploadBaseDir(uploadDir.toString());
|
||||||
properties.setDirectCpconfigFileName("cpconfig.cfg");
|
properties.setDirectCpconfigFileName("cpconfig.cfg");
|
||||||
|
properties.setDirectCpconfigTargetPath(cpconfig.toString());
|
||||||
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
InitTaskEntity task = new InitTaskEntity();
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
@@ -190,51 +167,49 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
"orgNameEn", "TEST BANK",
|
"orgNameEn", "TEST BANK",
|
||||||
"deployMode", "DUAL",
|
"deployMode", "DUAL",
|
||||||
"nodes", Map.of("node01Ip", "10.0.1.1", "node02Ip", "10.0.1.2"),
|
"nodes", Map.of("node01Ip", "10.0.1.1", "node02Ip", "10.0.1.2"),
|
||||||
"mq", Map.of("mqType", "RABBITMQ_CFMQ", "cfmqConfigFileId", "cfmq-001"),
|
"mq", Map.of("mqType", "RABBITMQ_CFMQ", "cfgZipFileId", "cae-001", "cfmqConfigFileId", "cfmq-001")
|
||||||
"licenses", Map.of("cfgZipFileId", "cfg-001"),
|
|
||||||
"signServer", Map.of(
|
|
||||||
"signHost", "172.30.1.101",
|
|
||||||
"signPort", 50006,
|
|
||||||
"signType", "Infosec",
|
|
||||||
"signCertDn", "CN=TEST,OU=CIPS",
|
|
||||||
"signCertSn", "123456",
|
|
||||||
"signPassword", "secret"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
InitTaskStepEntity step = new InitTaskStepEntity();
|
InitTaskStepEntity renderStep = new InitTaskStepEntity();
|
||||||
step.setStepNo(1);
|
renderStep.setStepNo(1);
|
||||||
step.setStepCode("RENDER_CONFIG");
|
renderStep.setStepCode("RENDER_CONFIG");
|
||||||
step.setCommandLine("internal::render_config");
|
renderStep.setCommandLine("internal::render_config");
|
||||||
|
InitStepExecutionResult renderResult = executor.execute(task, renderStep);
|
||||||
|
|
||||||
InitStepExecutionResult result = executor.execute(task, step);
|
Assertions.assertTrue(renderResult.isSuccess());
|
||||||
|
Path renderedPath = parseRenderedCpconfigPath(renderResult.getMessage());
|
||||||
Assertions.assertTrue(result.isSuccess());
|
|
||||||
Assertions.assertNotNull(result.getLogPath());
|
|
||||||
Path renderedPath = parseRenderedCpconfigPath(result.getMessage());
|
|
||||||
String rendered = Files.readString(renderedPath);
|
String rendered = Files.readString(renderedPath);
|
||||||
Assertions.assertTrue(rendered.contains("MY_CIPSID_OR_BIC=AAAABBBBXXX"));
|
Assertions.assertTrue(rendered.contains("MY_CIPSID_OR_BIC=AAAABBBBXXX"));
|
||||||
Assertions.assertTrue(rendered.contains("MQ_TYPE=3"));
|
Assertions.assertTrue(rendered.contains("MQ_TYPE=3"));
|
||||||
Assertions.assertTrue(rendered.contains("node_01_ip=10.0.1.1"));
|
Assertions.assertTrue(rendered.contains("node_01_ip=10.0.1.1"));
|
||||||
Assertions.assertTrue(rendered.contains("node_02_ip=10.0.1.2"));
|
Assertions.assertTrue(rendered.contains("node_02_ip=10.0.1.2"));
|
||||||
Assertions.assertTrue(rendered.contains("sign_host=172.30.1.101"));
|
Assertions.assertTrue(rendered.contains("db_ip=127.0.0.1"));
|
||||||
|
|
||||||
|
InitTaskStepEntity verifyStep = new InitTaskStepEntity();
|
||||||
|
verifyStep.setStepNo(2);
|
||||||
|
verifyStep.setStepCode("VERIFY");
|
||||||
|
verifyStep.setCommandLine("internal::verify");
|
||||||
|
InitStepExecutionResult verifyResult = executor.execute(task, verifyStep);
|
||||||
|
Assertions.assertTrue(verifyResult.isSuccess());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldApplyCfmqConfigToTargetDirectory() throws IOException {
|
void shouldApplyDirectCfmqLinkScript() throws IOException {
|
||||||
Path tempRoot = Files.createTempDirectory("init-executor-cfmq-test");
|
Path tempRoot = Files.createTempDirectory("init-executor-cfmq-link-test");
|
||||||
Path uploadDir = tempRoot.resolve("uploads");
|
Path uploadDir = tempRoot.resolve("uploads");
|
||||||
Files.createDirectories(uploadDir);
|
Files.createDirectories(uploadDir);
|
||||||
Path cfmqSource = uploadDir.resolve("cfmq-001");
|
Path cfmqSource = uploadDir.resolve("cfmq-001");
|
||||||
Files.writeString(cfmqSource, "cfmq.host=127.0.0.1");
|
Path marker = tempRoot.resolve("cfmq-link.marker");
|
||||||
|
Files.writeString(cfmqSource, "printf '%s' /cfmq/cfmq-server > '" + marker + "'\n");
|
||||||
|
|
||||||
Path targetDir = tempRoot.resolve("target");
|
Path targetDir = tempRoot.resolve("cfmq-install");
|
||||||
InitExecutorProperties properties = new InitExecutorProperties();
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
properties.setMode(InitExecutorProperties.Mode.LOCAL);
|
||||||
properties.setLogDir(tempRoot.resolve("logs").toString());
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
properties.setUploadBaseDir(uploadDir.toString());
|
properties.setUploadBaseDir(uploadDir.toString());
|
||||||
properties.setCfmqTargetDir(targetDir.toString());
|
properties.setStagingRootDir(tempRoot.resolve("staging").toString());
|
||||||
|
properties.setDirectCfmqInstallPath(targetDir.toString());
|
||||||
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
InitTaskEntity task = new InitTaskEntity();
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
@@ -249,45 +224,45 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
"orgNameEn", "TEST BANK",
|
"orgNameEn", "TEST BANK",
|
||||||
"deployMode", "SINGLE",
|
"deployMode", "SINGLE",
|
||||||
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
||||||
"mq", Map.of("mqType", "RABBITMQ_CFMQ", "cfmqConfigFileId", "cfmq-001"),
|
"mq", Map.of("mqType", "RABBITMQ_CFMQ", "cfgZipFileId", "cae-001", "cfmqConfigFileId", "cfmq-001")
|
||||||
"licenses", Map.of("cfgZipFileId", "cfg-001"),
|
|
||||||
"signServer", Map.of(
|
|
||||||
"signHost", "172.30.1.101",
|
|
||||||
"signPort", 50006,
|
|
||||||
"signType", "Infosec",
|
|
||||||
"signCertDn", "CN=TEST,OU=CIPS",
|
|
||||||
"signCertSn", "123456",
|
|
||||||
"signPassword", "secret"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
InitTaskStepEntity step = new InitTaskStepEntity();
|
InitTaskStepEntity step = new InitTaskStepEntity();
|
||||||
step.setStepNo(1);
|
step.setStepNo(1);
|
||||||
step.setStepCode("CFMQ_APPLY");
|
step.setStepCode("CFMQ_LINK_APPLY");
|
||||||
step.setCommandLine("internal::cfmq_apply");
|
step.setCommandLine("internal::cfmq_link_apply");
|
||||||
|
|
||||||
InitStepExecutionResult result = executor.execute(task, step);
|
InitStepExecutionResult result = executor.execute(task, step);
|
||||||
|
|
||||||
Assertions.assertTrue(result.isSuccess());
|
Assertions.assertTrue(result.isSuccess());
|
||||||
Path copied = targetDir.resolve(cfmqSource.getFileName());
|
Assertions.assertTrue(Files.exists(marker));
|
||||||
Assertions.assertTrue(Files.exists(copied));
|
Assertions.assertEquals(targetDir.toString(), Files.readString(marker));
|
||||||
Assertions.assertEquals("cfmq.host=127.0.0.1", Files.readString(copied));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldSimulateDirectTlqInitCfgStep() throws IOException {
|
void shouldApplyDirectCaePackageToTargetDirectory() throws IOException {
|
||||||
Path tempRoot = Files.createTempDirectory("init-executor-tlq-init-test");
|
Path tempRoot = Files.createTempDirectory("init-executor-cae-package-test");
|
||||||
Path uploadDir = tempRoot.resolve("uploads");
|
Path uploadDir = tempRoot.resolve("uploads");
|
||||||
Files.createDirectories(uploadDir);
|
Files.createDirectories(uploadDir);
|
||||||
|
Path caeZip = uploadDir.resolve("cae-001");
|
||||||
|
writeZip(caeZip, Map.of(
|
||||||
|
"route/route_demo.ini", "NAME=MSGMB_1\n",
|
||||||
|
"pmtsmsghdl.cfg", "handler=old\n",
|
||||||
|
"bin/tlq_gateway.sh", "gateway=127.0.0.1\n"
|
||||||
|
));
|
||||||
|
|
||||||
|
Path targetDir = tempRoot.resolve("pmts/cfg");
|
||||||
InitExecutorProperties properties = new InitExecutorProperties();
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
properties.setMode(InitExecutorProperties.Mode.LOCAL);
|
||||||
properties.setLogDir(tempRoot.resolve("logs").toString());
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
properties.setUploadBaseDir(uploadDir.toString());
|
properties.setUploadBaseDir(uploadDir.toString());
|
||||||
|
properties.setStagingRootDir(tempRoot.resolve("staging").toString());
|
||||||
|
properties.setDirectCaeTargetDir(targetDir.toString());
|
||||||
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
InitTaskEntity task = new InitTaskEntity();
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
task.setTaskId("TASK-TLQ-INIT-1");
|
task.setTaskId("TASK-CAE-PACKAGE-1");
|
||||||
task.setProductType("DIRECT");
|
task.setProductType("DIRECT");
|
||||||
task.setInitPlanJson(buildInitPlanJson(
|
task.setInitPlanJson(buildInitPlanJson(
|
||||||
"DIRECT",
|
"DIRECT",
|
||||||
@@ -296,33 +271,112 @@ class ConfigurableInitStepExecutorTest {
|
|||||||
"orgCode", "AAAABBBBXXX",
|
"orgCode", "AAAABBBBXXX",
|
||||||
"orgNameCn", "测试机构",
|
"orgNameCn", "测试机构",
|
||||||
"orgNameEn", "TEST BANK",
|
"orgNameEn", "TEST BANK",
|
||||||
"deployMode", "DUAL",
|
"deployMode", "SINGLE",
|
||||||
"nodes", Map.of("node01Ip", "10.0.1.1", "node02Ip", "10.0.1.2"),
|
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
||||||
"mq", Map.of("mqType", "RABBITMQ_TLQ", "tlqLicenseFileId", "file-tlq-001"),
|
"mq", Map.of("mqType", "RABBITMQ_TLQ", "cipsGatewayHost", "172.30.1.10", "cfgZipFileId", "cae-001")
|
||||||
"licenses", Map.of("cfgZipFileId", "cfg-001"),
|
|
||||||
"signServer", Map.of(
|
|
||||||
"signHost", "172.30.1.101",
|
|
||||||
"signPort", 50006,
|
|
||||||
"signType", "Infosec",
|
|
||||||
"signCertDn", "CN=TEST,OU=CIPS",
|
|
||||||
"signCertSn", "123456",
|
|
||||||
"signPassword", "secret"
|
|
||||||
),
|
|
||||||
"directTlq", Map.of(
|
|
||||||
"localNodeSeq", "A",
|
|
||||||
"upstreamInstitutions", "CIPSCNSHXXX;CIPSCNWXXXX",
|
|
||||||
"upstreamCocCount", 2
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
|
|
||||||
InitTaskStepEntity step = new InitTaskStepEntity();
|
InitTaskStepEntity step = new InitTaskStepEntity();
|
||||||
step.setStepNo(1);
|
step.setStepNo(1);
|
||||||
step.setStepCode("TLQ_INIT_CFG");
|
step.setStepCode("CAE_PACKAGE_APPLY");
|
||||||
step.setCommandLine("internal::tlq_init_cfg");
|
step.setCommandLine("internal::cae_package_apply");
|
||||||
|
|
||||||
InitStepExecutionResult result = executor.execute(task, step);
|
InitStepExecutionResult result = executor.execute(task, step);
|
||||||
|
|
||||||
Assertions.assertTrue(result.isSuccess());
|
Assertions.assertTrue(result.isSuccess());
|
||||||
|
Assertions.assertTrue(Files.exists(targetDir.resolve("route/route_demo.ini")));
|
||||||
|
Assertions.assertTrue(Files.exists(targetDir.resolve("pmtsmsghdl.cfg")));
|
||||||
|
Assertions.assertTrue(Files.exists(targetDir.resolve("bin/tlq_gateway.sh")));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldApplyDirectTlqGatewayScript() throws IOException {
|
||||||
|
Path tempRoot = Files.createTempDirectory("init-executor-tlq-gateway-test");
|
||||||
|
Path caeTargetDir = tempRoot.resolve("pmts/cfg");
|
||||||
|
Path gatewaySource = caeTargetDir.resolve("bin/tlq_gateway.sh");
|
||||||
|
Files.createDirectories(gatewaySource.getParent());
|
||||||
|
Files.writeString(gatewaySource, "gateway=127.0.0.1\n");
|
||||||
|
|
||||||
|
Path tlqTargetDir = tempRoot.resolve("tlq/bin");
|
||||||
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
|
properties.setMode(InitExecutorProperties.Mode.LOCAL);
|
||||||
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
|
properties.setDirectCaeTargetDir(caeTargetDir.toString());
|
||||||
|
properties.setDirectTlqGatewayScriptTargetDir(tlqTargetDir.toString());
|
||||||
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
|
task.setTaskId("TASK-TLQ-GATEWAY-1");
|
||||||
|
task.setProductType("DIRECT");
|
||||||
|
task.setInitPlanJson(buildInitPlanJson(
|
||||||
|
"DIRECT",
|
||||||
|
Map.of(
|
||||||
|
"orgCodeType", "BIC",
|
||||||
|
"orgCode", "AAAABBBBXXX",
|
||||||
|
"orgNameCn", "测试机构",
|
||||||
|
"orgNameEn", "TEST BANK",
|
||||||
|
"deployMode", "SINGLE",
|
||||||
|
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
||||||
|
"mq", Map.of("mqType", "RABBITMQ_TLQ", "cipsGatewayHost", "172.30.1.10", "cfgZipFileId", "cae-001")
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
InitTaskStepEntity step = new InitTaskStepEntity();
|
||||||
|
step.setStepNo(1);
|
||||||
|
step.setStepCode("TLQ_GATEWAY_APPLY");
|
||||||
|
step.setCommandLine("internal::tlq_gateway_apply");
|
||||||
|
|
||||||
|
InitStepExecutionResult result = executor.execute(task, step);
|
||||||
|
|
||||||
|
Assertions.assertTrue(result.isSuccess());
|
||||||
|
Path copied = tlqTargetDir.resolve("tlq_gateway.sh");
|
||||||
|
Assertions.assertTrue(Files.exists(copied));
|
||||||
|
Assertions.assertTrue(Files.readString(copied).contains("172.30.1.10"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRewriteDirectCfmqRouteConfig() throws IOException {
|
||||||
|
Path tempRoot = Files.createTempDirectory("init-executor-cfmq-route-test");
|
||||||
|
Path caeTargetDir = tempRoot.resolve("pmts/cfg");
|
||||||
|
Path routeFile = caeTargetDir.resolve("route/route_demo.ini");
|
||||||
|
Path pmtsMsgHdl = caeTargetDir.resolve("pmtsmsghdl.cfg");
|
||||||
|
Files.createDirectories(routeFile.getParent());
|
||||||
|
Files.writeString(routeFile, "route.target=MSGMB_1\n");
|
||||||
|
Files.writeString(pmtsMsgHdl, "handler=old\n");
|
||||||
|
|
||||||
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
|
properties.setMode(InitExecutorProperties.Mode.LOCAL);
|
||||||
|
properties.setLogDir(tempRoot.resolve("logs").toString());
|
||||||
|
properties.setDirectCaeTargetDir(caeTargetDir.toString());
|
||||||
|
ConfigurableInitStepExecutor executor = new ConfigurableInitStepExecutor(properties, new ObjectMapper());
|
||||||
|
|
||||||
|
InitTaskEntity task = new InitTaskEntity();
|
||||||
|
task.setTaskId("TASK-CFMQ-ROUTE-1");
|
||||||
|
task.setProductType("DIRECT");
|
||||||
|
task.setInitPlanJson(buildInitPlanJson(
|
||||||
|
"DIRECT",
|
||||||
|
Map.of(
|
||||||
|
"orgCodeType", "BIC",
|
||||||
|
"orgCode", "AAAABBBBXXX",
|
||||||
|
"orgNameCn", "测试机构",
|
||||||
|
"orgNameEn", "TEST BANK",
|
||||||
|
"deployMode", "SINGLE",
|
||||||
|
"nodes", Map.of("node01Ip", "10.0.1.1"),
|
||||||
|
"mq", Map.of("mqType", "RABBITMQ_CFMQ", "cfgZipFileId", "cae-001", "cfmqConfigFileId", "cfmq-001")
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
InitTaskStepEntity step = new InitTaskStepEntity();
|
||||||
|
step.setStepNo(1);
|
||||||
|
step.setStepCode("CFMQ_ROUTE_APPLY");
|
||||||
|
step.setCommandLine("internal::cfmq_route_apply");
|
||||||
|
|
||||||
|
InitStepExecutionResult result = executor.execute(task, step);
|
||||||
|
|
||||||
|
Assertions.assertTrue(result.isSuccess());
|
||||||
|
Assertions.assertTrue(Files.readString(routeFile).contains("MSGTOMB_1"));
|
||||||
|
Assertions.assertFalse(Files.exists(pmtsMsgHdl));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.cisd.tms.modules.init.service;
|
|||||||
|
|
||||||
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
import com.cisd.tms.common.config.properties.CisdPresetProperties;
|
||||||
import com.cisd.tms.common.exception.BizException;
|
import com.cisd.tms.common.exception.BizException;
|
||||||
|
import com.cisd.tms.modules.file.entity.FileRecordEntity;
|
||||||
|
import com.cisd.tms.modules.file.repository.FileRecordRepository;
|
||||||
import com.cisd.tms.modules.init.config.InitCommandProfileService;
|
import com.cisd.tms.modules.init.config.InitCommandProfileService;
|
||||||
import com.cisd.tms.modules.init.config.InitExecutorProperties;
|
import com.cisd.tms.modules.init.config.InitExecutorProperties;
|
||||||
import com.cisd.tms.modules.init.dto.InitCreateTaskResponse;
|
import com.cisd.tms.modules.init.dto.InitCreateTaskResponse;
|
||||||
@@ -35,6 +37,7 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
@@ -106,29 +109,34 @@ class InitServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRequireDirectSpecificFieldsForCfmqMode() {
|
void shouldRequireMqCfgZipForDirectTlqMode() {
|
||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
|
||||||
InitPreviewRequest request = validDirectRequest();
|
|
||||||
request.getMq().setMqType("RABBITMQ_CFMQ");
|
|
||||||
request.getMq().setCfmqConfigFileId(null);
|
|
||||||
request.getLicenses().setCfgZipFileId(null);
|
|
||||||
|
|
||||||
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
|
||||||
Assertions.assertTrue(
|
|
||||||
ex.getMessage().contains("licenses.cfgZipFileId") || ex.getMessage().contains("mq.cfmqConfigFileId")
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldRequireDirectTlqConfigForTlqMode() {
|
|
||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
request.getMq().setCfgZipFileId(null);
|
||||||
request.setDirectTlq(null);
|
|
||||||
|
|
||||||
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
||||||
Assertions.assertTrue(ex.getMessage().contains("directTlq"));
|
Assertions.assertTrue(ex.getMessage().contains("mq.cfgZipFileId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRequireMqCfmqConfigFileIdForDirectCfmqMode() {
|
||||||
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
|
InitPreviewRequest request = validDirectRequest();
|
||||||
|
request.getMq().setCfmqConfigFileId(null);
|
||||||
|
|
||||||
|
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
||||||
|
Assertions.assertTrue(ex.getMessage().contains("mq.cfmqConfigFileId"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRequireMqCfgZipForDirectCfmqMode() {
|
||||||
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
|
InitPreviewRequest request = validDirectRequest();
|
||||||
|
request.getMq().setCfgZipFileId(null);
|
||||||
|
|
||||||
|
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
||||||
|
Assertions.assertTrue(ex.getMessage().contains("mq.cfgZipFileId"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -136,33 +144,20 @@ class InitServiceTest {
|
|||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
|
||||||
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
||||||
request.setDirectTlq(directTlqConfig());
|
request.getMq().setCfgZipFileId("file-direct-tlq-cfg-001");
|
||||||
|
|
||||||
InitPreviewResponse response = service.preview(request);
|
InitPreviewResponse response = service.preview(request);
|
||||||
Assertions.assertEquals("DIRECT", response.getResolvedProductType());
|
Assertions.assertEquals("DIRECT", response.getResolvedProductType());
|
||||||
Assertions.assertTrue(response.getStepCount() >= 1);
|
Assertions.assertTrue(response.getStepCount() >= 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void shouldAcceptDirectCfmqModeWithoutSignServer() {
|
|
||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
|
||||||
InitPreviewRequest request = validDirectRequest();
|
|
||||||
|
|
||||||
InitPreviewResponse response = service.preview(request);
|
|
||||||
|
|
||||||
Assertions.assertEquals("DIRECT", response.getResolvedProductType());
|
|
||||||
Assertions.assertTrue(response.getStepCount() >= 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRequireCipsGatewayHostForDirectTlqMode() {
|
void shouldRequireCipsGatewayHostForDirectTlqMode() {
|
||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
request.getMq().setCfgZipFileId("file-direct-tlq-cfg-001");
|
||||||
request.setDirectTlq(directTlqConfig());
|
|
||||||
|
|
||||||
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
IllegalArgumentException ex = Assertions.assertThrows(IllegalArgumentException.class, () -> service.preview(request));
|
||||||
Assertions.assertTrue(ex.getMessage().contains("mq.cipsGatewayHost"));
|
Assertions.assertTrue(ex.getMessage().contains("mq.cipsGatewayHost"));
|
||||||
@@ -173,9 +168,8 @@ class InitServiceTest {
|
|||||||
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InitService service = newService(emptyRepository(), emptyStepRepository(), preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
|
||||||
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
||||||
request.setDirectTlq(directTlqConfig());
|
request.getMq().setCfgZipFileId("file-direct-tlq-cfg-001");
|
||||||
|
|
||||||
InitPreviewResponse response = service.preview(request);
|
InitPreviewResponse response = service.preview(request);
|
||||||
|
|
||||||
@@ -245,7 +239,16 @@ class InitServiceTest {
|
|||||||
void shouldLoadCurrentInitConfigFromLatestSuccessfulInitTask() {
|
void shouldLoadCurrentInitConfigFromLatestSuccessfulInitTask() {
|
||||||
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
||||||
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
||||||
InitService service = newService(repository, stepRepository, preset("ENTERPRISE", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InMemoryFileRecordRepository fileRepository = new InMemoryFileRecordRepository();
|
||||||
|
fileRepository.save(record("file-receiver-001", "receiver-license.dat"));
|
||||||
|
InitService service = newService(
|
||||||
|
repository,
|
||||||
|
stepRepository,
|
||||||
|
fileRepository,
|
||||||
|
preset("ENTERPRISE", "V1.3.2", "CONFIG"),
|
||||||
|
successExecutor(),
|
||||||
|
"/tmp/tms-init-logs"
|
||||||
|
);
|
||||||
InitPreviewRequest request = validEnterpriseRequest();
|
InitPreviewRequest request = validEnterpriseRequest();
|
||||||
request.setOrgNameEn("Test Organization");
|
request.setOrgNameEn("Test Organization");
|
||||||
request.getNodes().setNode02Ip("10.0.0.2");
|
request.getNodes().setNode02Ip("10.0.0.2");
|
||||||
@@ -263,6 +266,9 @@ class InitServiceTest {
|
|||||||
Assertions.assertEquals("cisd_channel_user", response.getChannelUsername());
|
Assertions.assertEquals("cisd_channel_user", response.getChannelUsername());
|
||||||
Assertions.assertEquals("10.0.0.1", response.getNode01Ip());
|
Assertions.assertEquals("10.0.0.1", response.getNode01Ip());
|
||||||
Assertions.assertEquals("10.0.0.2", response.getNode02Ip());
|
Assertions.assertEquals("10.0.0.2", response.getNode02Ip());
|
||||||
|
Assertions.assertEquals("receiver-license.dat", response.getReceiverLicenseFileName());
|
||||||
|
Assertions.assertTrue(response.getTlqFileNames().isEmpty());
|
||||||
|
Assertions.assertTrue(response.getCfmqFileNames().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -298,12 +304,22 @@ class InitServiceTest {
|
|||||||
void shouldLoadCurrentInitConfigWithDirectTlqGatewayHost() {
|
void shouldLoadCurrentInitConfigWithDirectTlqGatewayHost() {
|
||||||
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
||||||
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
||||||
InitService service = newService(repository, stepRepository, preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InMemoryFileRecordRepository fileRepository = new InMemoryFileRecordRepository();
|
||||||
|
fileRepository.save(record("file-direct-tlq-license-001", "tlq-license.dat"));
|
||||||
|
fileRepository.save(record("file-direct-tlq-cfg-001", "CFG_AAAABBBBXXX_01COCATEST_CAEA.zip"));
|
||||||
|
InitService service = newService(
|
||||||
|
repository,
|
||||||
|
stepRepository,
|
||||||
|
fileRepository,
|
||||||
|
preset("DIRECT", "V1.3.2", "CONFIG"),
|
||||||
|
successExecutor(),
|
||||||
|
"/tmp/tms-init-logs"
|
||||||
|
);
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
|
||||||
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
||||||
request.setDirectTlq(directTlqConfig());
|
request.getMq().setTlqLicenseFileId("file-direct-tlq-license-001");
|
||||||
|
request.getMq().setCfgZipFileId("file-direct-tlq-cfg-001");
|
||||||
createSuccessfulInitTask(service, request);
|
createSuccessfulInitTask(service, request);
|
||||||
|
|
||||||
CurrentInitConfigResponse response = service.loadCurrentInitConfig();
|
CurrentInitConfigResponse response = service.loadCurrentInitConfig();
|
||||||
@@ -311,6 +327,44 @@ class InitServiceTest {
|
|||||||
Assertions.assertEquals("DIRECT", response.getProductType());
|
Assertions.assertEquals("DIRECT", response.getProductType());
|
||||||
Assertions.assertEquals("RABBITMQ_TLQ", response.getMqType());
|
Assertions.assertEquals("RABBITMQ_TLQ", response.getMqType());
|
||||||
Assertions.assertEquals("192.168.10.20", readCurrentInitConfigCipsGatewayHost(response));
|
Assertions.assertEquals("192.168.10.20", readCurrentInitConfigCipsGatewayHost(response));
|
||||||
|
assertGetterMissing(response, "getDbHost");
|
||||||
|
assertGetterMissing(response, "getDbPort");
|
||||||
|
Assertions.assertNull(response.getReceiverLicenseFileName());
|
||||||
|
Assertions.assertEquals(
|
||||||
|
List.of("tlq-license.dat", "CFG_AAAABBBBXXX_01COCATEST_CAEA.zip"),
|
||||||
|
response.getTlqFileNames()
|
||||||
|
);
|
||||||
|
Assertions.assertTrue(response.getCfmqFileNames().isEmpty());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldLoadCurrentInitConfigWithDirectCfmqFilesSeparated() {
|
||||||
|
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
||||||
|
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
||||||
|
InMemoryFileRecordRepository fileRepository = new InMemoryFileRecordRepository();
|
||||||
|
fileRepository.save(record("file-direct-cfmq-cfg-001", "CFG_AAAABBBBXXX_01COCATEST_CAEA.zip"));
|
||||||
|
fileRepository.save(record("file-direct-cfmq-addlink-001", "addlink_CFQMAAAABBBBXXXA.sh"));
|
||||||
|
InitService service = newService(
|
||||||
|
repository,
|
||||||
|
stepRepository,
|
||||||
|
fileRepository,
|
||||||
|
preset("DIRECT", "V1.3.2", "CONFIG"),
|
||||||
|
successExecutor(),
|
||||||
|
"/tmp/tms-init-logs"
|
||||||
|
);
|
||||||
|
InitPreviewRequest request = validDirectRequest();
|
||||||
|
createSuccessfulInitTask(service, request);
|
||||||
|
|
||||||
|
CurrentInitConfigResponse response = service.loadCurrentInitConfig();
|
||||||
|
|
||||||
|
Assertions.assertEquals("DIRECT", response.getProductType());
|
||||||
|
Assertions.assertEquals("RABBITMQ_CFMQ", response.getMqType());
|
||||||
|
Assertions.assertNull(response.getReceiverLicenseFileName());
|
||||||
|
Assertions.assertTrue(response.getTlqFileNames().isEmpty());
|
||||||
|
Assertions.assertEquals(
|
||||||
|
List.of("CFG_AAAABBBBXXX_01COCATEST_CAEA.zip", "addlink_CFQMAAAABBBBXXXA.sh"),
|
||||||
|
response.getCfmqFileNames()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -448,21 +502,51 @@ class InitServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldNotPlanStandardPostDeployStepsForDirectMode() {
|
void shouldPlanDirectTlqSteps() {
|
||||||
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
||||||
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
||||||
InitService service = newService(repository, stepRepository, preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
InitService service = newService(repository, stepRepository, preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
|
|
||||||
InitPreviewRequest request = validDirectRequest();
|
InitPreviewRequest request = validDirectRequest();
|
||||||
request.getMq().setMqType("RABBITMQ_TLQ");
|
request.getMq().setMqType("RABBITMQ_TLQ");
|
||||||
request.getMq().setTlqLicenseFileId("file-tlq-001");
|
|
||||||
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
setMqCipsGatewayHost(request.getMq(), "192.168.10.20");
|
||||||
request.setDirectTlq(directTlqConfig());
|
request.getMq().setCfgZipFileId("file-direct-tlq-cfg-001");
|
||||||
|
|
||||||
InitCreateTaskResponse created = service.createTask(request);
|
InitCreateTaskResponse created = service.createTask(request);
|
||||||
List<InitTaskStepResponse> steps = service.getTaskSteps(created.getTaskId());
|
List<InitTaskStepResponse> steps = service.getTaskSteps(created.getTaskId());
|
||||||
List<String> stepCodes = steps.stream().map(InitTaskStepResponse::getStepCode).toList();
|
List<String> stepCodes = steps.stream().map(InitTaskStepResponse::getStepCode).toList();
|
||||||
|
|
||||||
|
Assertions.assertEquals(List.of(
|
||||||
|
"RENDER_CONFIG",
|
||||||
|
"MQ_USER_APPLY",
|
||||||
|
"CAE_PACKAGE_APPLY",
|
||||||
|
"TLQ_GATEWAY_APPLY",
|
||||||
|
"CAE_UPDATE",
|
||||||
|
"RESTART_TLQ",
|
||||||
|
"VERIFY"
|
||||||
|
), stepCodes);
|
||||||
|
assertNotContainsStandardPostDeploySteps(stepCodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldPlanDirectCfmqSteps() {
|
||||||
|
InMemoryInitTaskRepository repository = new InMemoryInitTaskRepository();
|
||||||
|
InMemoryInitTaskStepRepository stepRepository = new InMemoryInitTaskStepRepository();
|
||||||
|
InitService service = newService(repository, stepRepository, preset("DIRECT", "V1.3.2", "CONFIG"), successExecutor(), "/tmp/tms-init-logs");
|
||||||
|
|
||||||
|
InitCreateTaskResponse created = service.createTask(validDirectRequest());
|
||||||
|
List<InitTaskStepResponse> steps = service.getTaskSteps(created.getTaskId());
|
||||||
|
List<String> stepCodes = steps.stream().map(InitTaskStepResponse::getStepCode).toList();
|
||||||
|
|
||||||
|
Assertions.assertEquals(List.of(
|
||||||
|
"RENDER_CONFIG",
|
||||||
|
"MQ_USER_APPLY",
|
||||||
|
"CFMQ_LINK_APPLY",
|
||||||
|
"CAE_PACKAGE_APPLY",
|
||||||
|
"CFMQ_ROUTE_APPLY",
|
||||||
|
"CAE_UPDATE",
|
||||||
|
"VERIFY"
|
||||||
|
), stepCodes);
|
||||||
assertNotContainsStandardPostDeploySteps(stepCodes);
|
assertNotContainsStandardPostDeploySteps(stepCodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -689,13 +773,33 @@ class InitServiceTest {
|
|||||||
CisdPresetProperties preset,
|
CisdPresetProperties preset,
|
||||||
InitStepExecutor executor,
|
InitStepExecutor executor,
|
||||||
String logDir
|
String logDir
|
||||||
|
) {
|
||||||
|
return newService(taskRepository, stepRepository, new InMemoryFileRecordRepository(), preset, executor, logDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InitService newService(
|
||||||
|
InitTaskRepository taskRepository,
|
||||||
|
InitTaskStepRepository stepRepository,
|
||||||
|
FileRecordRepository fileRecordRepository,
|
||||||
|
CisdPresetProperties preset,
|
||||||
|
InitStepExecutor executor,
|
||||||
|
String logDir
|
||||||
) {
|
) {
|
||||||
InitExecutorProperties properties = new InitExecutorProperties();
|
InitExecutorProperties properties = new InitExecutorProperties();
|
||||||
properties.setLogDir(logDir);
|
properties.setLogDir(logDir);
|
||||||
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
properties.setMode(InitExecutorProperties.Mode.SIMULATE);
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
ObjectMapper objectMapper = new ObjectMapper();
|
||||||
InitCommandProfileService commandProfileService = new InitCommandProfileService(objectMapper, properties);
|
InitCommandProfileService commandProfileService = new InitCommandProfileService(objectMapper, properties);
|
||||||
return new InitServiceImpl(taskRepository, stepRepository, preset, objectMapper, executor, commandProfileService, properties);
|
return new InitServiceImpl(
|
||||||
|
taskRepository,
|
||||||
|
stepRepository,
|
||||||
|
fileRecordRepository,
|
||||||
|
preset,
|
||||||
|
objectMapper,
|
||||||
|
executor,
|
||||||
|
commandProfileService,
|
||||||
|
properties
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InitTaskRepository emptyRepository() {
|
private static InitTaskRepository emptyRepository() {
|
||||||
@@ -786,13 +890,12 @@ class InitServiceTest {
|
|||||||
InitPreviewRequest request = validEnterpriseRequest();
|
InitPreviewRequest request = validEnterpriseRequest();
|
||||||
request.setDeployMode("DUAL");
|
request.setDeployMode("DUAL");
|
||||||
request.getNodes().setNode02Ip("10.0.0.2");
|
request.getNodes().setNode02Ip("10.0.0.2");
|
||||||
|
request.setLicenses(null);
|
||||||
|
|
||||||
InitPreviewRequest.Mq mq = request.getMq();
|
InitPreviewRequest.Mq mq = request.getMq();
|
||||||
mq.setMqType("RABBITMQ_CFMQ");
|
mq.setMqType("RABBITMQ_CFMQ");
|
||||||
mq.setCfmqConfigFileId("file-cfmq-001");
|
mq.setCfgZipFileId("file-direct-cfmq-cfg-001");
|
||||||
|
mq.setCfmqConfigFileId("file-direct-cfmq-addlink-001");
|
||||||
InitPreviewRequest.Licenses licenses = request.getLicenses();
|
|
||||||
licenses.setCfgZipFileId("file-cfg-001");
|
|
||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -802,14 +905,6 @@ class InitServiceTest {
|
|||||||
awaitTaskStatus(service, created.getTaskId(), "SUCCESS");
|
awaitTaskStatus(service, created.getTaskId(), "SUCCESS");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static InitPreviewRequest.DirectTlqConfig directTlqConfig() {
|
|
||||||
InitPreviewRequest.DirectTlqConfig config = new InitPreviewRequest.DirectTlqConfig();
|
|
||||||
config.setLocalNodeSeq("A");
|
|
||||||
config.setUpstreamInstitutions("CIPSCNSHXXX;CIPSCNWXXXX");
|
|
||||||
config.setUpstreamCocCount(2);
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void setMqCipsGatewayHost(InitPreviewRequest.Mq mq, String value) {
|
private static void setMqCipsGatewayHost(InitPreviewRequest.Mq mq, String value) {
|
||||||
try {
|
try {
|
||||||
mq.getClass().getMethod("setCipsGatewayHost", String.class).invoke(mq, value);
|
mq.getClass().getMethod("setCipsGatewayHost", String.class).invoke(mq, value);
|
||||||
@@ -826,6 +921,34 @@ class InitServiceTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void assertGetterMissing(Object target, String getterName) {
|
||||||
|
Assertions.assertThrows(NoSuchMethodException.class, () -> target.getClass().getMethod(getterName));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileRecordEntity record(String fileId, String originalFilename) {
|
||||||
|
FileRecordEntity entity = new FileRecordEntity();
|
||||||
|
entity.setFileId(fileId);
|
||||||
|
entity.setOriginalFilename(originalFilename);
|
||||||
|
entity.setStoragePath("/tmp/uploads/" + fileId + "/" + originalFilename);
|
||||||
|
entity.setStatus("ACTIVE");
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class InMemoryFileRecordRepository implements FileRecordRepository {
|
||||||
|
|
||||||
|
private final Map<String, FileRecordEntity> store = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Optional<FileRecordEntity> findByFileId(String fileId) {
|
||||||
|
return Optional.ofNullable(store.get(fileId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(FileRecordEntity entity) {
|
||||||
|
store.put(entity.getFileId(), entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static void assertContainsStandardPostDeploySteps(List<String> stepCodes) {
|
private static void assertContainsStandardPostDeploySteps(List<String> stepCodes) {
|
||||||
Assertions.assertTrue(stepCodes.contains("DB_RENDER"));
|
Assertions.assertTrue(stepCodes.contains("DB_RENDER"));
|
||||||
Assertions.assertTrue(stepCodes.contains("DB_APPLY"));
|
Assertions.assertTrue(stepCodes.contains("DB_APPLY"));
|
||||||
|
|||||||
@@ -38,11 +38,13 @@ class UpgradeDtoContractTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldAcceptFileIdForCreateTaskRequest() {
|
void shouldAcceptFileIdAndTaskTypeForCreateTaskRequest() {
|
||||||
UpgradeCreateTaskRequest request = new UpgradeCreateTaskRequest();
|
UpgradeCreateTaskRequest request = new UpgradeCreateTaskRequest();
|
||||||
request.setFileId("FILE-20260319-000001");
|
request.setFileId("FILE-20260319-000001");
|
||||||
|
request.setTaskType("TMS");
|
||||||
|
|
||||||
Assertions.assertEquals("FILE-20260319-000001", request.getFileId());
|
Assertions.assertEquals("FILE-20260319-000001", request.getFileId());
|
||||||
|
Assertions.assertEquals("TMS", request.getTaskType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class UpgradeControllerTest {
|
|||||||
page.setPageSize(10);
|
page.setPageSize(10);
|
||||||
page.setTotal(1L);
|
page.setTotal(1L);
|
||||||
page.getItems().add(task);
|
page.getItems().add(task);
|
||||||
Mockito.when(upgradeService.listTasks(1, 10, "", "")).thenReturn(page);
|
Mockito.when(upgradeService.listTasks(1, 10, "", "", "2026-04-16")).thenReturn(page);
|
||||||
|
|
||||||
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new UpgradeController(upgradeService, fileService)).build();
|
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new UpgradeController(upgradeService, fileService)).build();
|
||||||
|
|
||||||
@@ -90,7 +90,7 @@ class UpgradeControllerTest {
|
|||||||
|
|
||||||
mockMvc.perform(post("/api/v1/upgrades")
|
mockMvc.perform(post("/api/v1/upgrades")
|
||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content("{\"fileId\":\"FILE-001\"}"))
|
.content("{\"fileId\":\"FILE-001\",\"taskType\":\"RECEIVER\"}"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"taskId\":\"UPG-001\"")));
|
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"taskId\":\"UPG-001\"")));
|
||||||
|
|
||||||
@@ -106,10 +106,13 @@ class UpgradeControllerTest {
|
|||||||
.param("page", "1")
|
.param("page", "1")
|
||||||
.param("pageSize", "10")
|
.param("pageSize", "10")
|
||||||
.param("taskType", "")
|
.param("taskType", "")
|
||||||
.param("status", ""))
|
.param("status", "")
|
||||||
|
.param("upgradeDate", "2026-04-16"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"total\":1")));
|
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"total\":1")));
|
||||||
|
|
||||||
|
Mockito.verify(upgradeService).listTasks(1, 10, "", "", "2026-04-16");
|
||||||
|
|
||||||
mockMvc.perform(get("/api/v1/upgrades/UPG-001"))
|
mockMvc.perform(get("/api/v1/upgrades/UPG-001"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"taskId\":\"UPG-001\"")));
|
.andExpect(content().string(org.hamcrest.Matchers.containsString("\"taskId\":\"UPG-001\"")));
|
||||||
|
|||||||
@@ -280,12 +280,19 @@ class UpgradeTaskRunnerTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public java.util.List<UpgradeTaskEntity> findPage(String taskType, String status, int offset, int limit) {
|
public java.util.List<UpgradeTaskEntity> findPage(
|
||||||
|
String taskType,
|
||||||
|
String status,
|
||||||
|
LocalDateTime startedAtBegin,
|
||||||
|
LocalDateTime startedAtEndExclusive,
|
||||||
|
int offset,
|
||||||
|
int limit
|
||||||
|
) {
|
||||||
return java.util.List.of();
|
return java.util.List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long countPage(String taskType, String status) {
|
public long countPage(String taskType, String status, LocalDateTime startedAtBegin, LocalDateTime startedAtEndExclusive) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
-4
@@ -47,12 +47,14 @@ class UpgradeTaskRepositoryTest {
|
|||||||
UpgradeTaskMapper mapper = Mockito.mock(UpgradeTaskMapper.class);
|
UpgradeTaskMapper mapper = Mockito.mock(UpgradeTaskMapper.class);
|
||||||
UpgradeTaskRepository repository = new UpgradeTaskRepositoryImpl(mapper);
|
UpgradeTaskRepository repository = new UpgradeTaskRepositoryImpl(mapper);
|
||||||
UpgradeTaskEntity entity = entity("UPG-003", "SUCCESS");
|
UpgradeTaskEntity entity = entity("UPG-003", "SUCCESS");
|
||||||
|
LocalDateTime startedAtBegin = LocalDateTime.of(2026, 4, 16, 0, 0, 0);
|
||||||
|
LocalDateTime startedAtEndExclusive = LocalDateTime.of(2026, 4, 17, 0, 0, 0);
|
||||||
|
|
||||||
Mockito.when(mapper.selectPage("TMS", "SUCCESS", 0, 10)).thenReturn(List.of(entity));
|
Mockito.when(mapper.selectPage("TMS", "SUCCESS", startedAtBegin, startedAtEndExclusive, 0, 10)).thenReturn(List.of(entity));
|
||||||
Mockito.when(mapper.countPage("TMS", "SUCCESS")).thenReturn(1L);
|
Mockito.when(mapper.countPage("TMS", "SUCCESS", startedAtBegin, startedAtEndExclusive)).thenReturn(1L);
|
||||||
|
|
||||||
List<UpgradeTaskEntity> page = repository.findPage("TMS", "SUCCESS", 0, 10);
|
List<UpgradeTaskEntity> page = repository.findPage("TMS", "SUCCESS", startedAtBegin, startedAtEndExclusive, 0, 10);
|
||||||
long total = repository.countPage("TMS", "SUCCESS");
|
long total = repository.countPage("TMS", "SUCCESS", startedAtBegin, startedAtEndExclusive);
|
||||||
|
|
||||||
Assertions.assertEquals(1, page.size());
|
Assertions.assertEquals(1, page.size());
|
||||||
Assertions.assertEquals("UPG-003", page.get(0).getTaskId());
|
Assertions.assertEquals("UPG-003", page.get(0).getTaskId());
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class UpgradeServiceTest {
|
|||||||
|
|
||||||
UpgradeCreateTaskRequest request = new UpgradeCreateTaskRequest();
|
UpgradeCreateTaskRequest request = new UpgradeCreateTaskRequest();
|
||||||
request.setFileId("FILE-001");
|
request.setFileId("FILE-001");
|
||||||
|
request.setTaskType("RECEIVER");
|
||||||
|
|
||||||
UpgradeCreateTaskResponse response = service.createTask(request);
|
UpgradeCreateTaskResponse response = service.createTask(request);
|
||||||
|
|
||||||
@@ -73,6 +74,42 @@ class UpgradeServiceTest {
|
|||||||
Assertions.assertTrue(response.getTaskId().startsWith("UPG-"));
|
Assertions.assertTrue(response.getTaskId().startsWith("UPG-"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldRejectCreateTaskWhenSelectedTaskTypeDoesNotMatchPreview() {
|
||||||
|
UpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||||
|
FileRecordRepository fileRecordRepository = Mockito.mock(FileRecordRepository.class);
|
||||||
|
UpgradePackageService packageService = Mockito.mock(UpgradePackageService.class);
|
||||||
|
UpgradeTaskRunner runner = Mockito.mock(UpgradeTaskRunner.class);
|
||||||
|
|
||||||
|
UpgradePreviewResponse preview = new UpgradePreviewResponse();
|
||||||
|
preview.setTaskType("RECEIVER");
|
||||||
|
preview.setProductType("DIRECT");
|
||||||
|
preview.setCurrentVersion("V1.3.1");
|
||||||
|
preview.setTargetVersion("V1.3.2");
|
||||||
|
preview.setAllowed(true);
|
||||||
|
preview.setVerifyPassed(true);
|
||||||
|
preview.setVerifyMessage("校验通过");
|
||||||
|
Mockito.when(packageService.preview("FILE-001")).thenReturn(preview);
|
||||||
|
|
||||||
|
UpgradeService service = new UpgradeService(
|
||||||
|
repository,
|
||||||
|
fileRecordRepository,
|
||||||
|
packageService,
|
||||||
|
runner,
|
||||||
|
properties(),
|
||||||
|
Runnable::run,
|
||||||
|
new ConcurrentHashMap<>()
|
||||||
|
);
|
||||||
|
|
||||||
|
UpgradeCreateTaskRequest request = new UpgradeCreateTaskRequest();
|
||||||
|
request.setFileId("FILE-001");
|
||||||
|
request.setTaskType("TMS");
|
||||||
|
|
||||||
|
BizException exception = Assertions.assertThrows(BizException.class, () -> service.createTask(request));
|
||||||
|
|
||||||
|
Assertions.assertEquals("selected taskType does not match package taskType", exception.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldRejectExecuteWhenAnotherTaskIsRunning() {
|
void shouldRejectExecuteWhenAnotherTaskIsRunning() {
|
||||||
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||||
@@ -110,12 +147,39 @@ class UpgradeServiceTest {
|
|||||||
new ConcurrentHashMap<>()
|
new ConcurrentHashMap<>()
|
||||||
);
|
);
|
||||||
|
|
||||||
UpgradeTaskPageResponse page = service.listTasks(1, 10, "", "");
|
UpgradeTaskPageResponse page = service.listTasks(1, 10, "", "", null);
|
||||||
|
|
||||||
Assertions.assertEquals(2L, page.getTotal());
|
Assertions.assertEquals(2L, page.getTotal());
|
||||||
Assertions.assertEquals(2, page.getItems().size());
|
Assertions.assertEquals(2, page.getItems().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldFilterUpgradeTasksByStartedAtDate() {
|
||||||
|
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||||
|
UpgradeTaskEntity sameDay = entity("UPG-001", "SUCCESS");
|
||||||
|
sameDay.setStartedAt(LocalDateTime.of(2026, 4, 16, 9, 30, 0));
|
||||||
|
repository.save(sameDay);
|
||||||
|
UpgradeTaskEntity anotherDay = entity("UPG-002", "FAILED");
|
||||||
|
anotherDay.setStartedAt(LocalDateTime.of(2026, 4, 15, 23, 59, 59));
|
||||||
|
repository.save(anotherDay);
|
||||||
|
|
||||||
|
UpgradeService service = new UpgradeService(
|
||||||
|
repository,
|
||||||
|
Mockito.mock(FileRecordRepository.class),
|
||||||
|
Mockito.mock(UpgradePackageService.class),
|
||||||
|
Mockito.mock(UpgradeTaskRunner.class),
|
||||||
|
properties(),
|
||||||
|
Runnable::run,
|
||||||
|
new ConcurrentHashMap<>()
|
||||||
|
);
|
||||||
|
|
||||||
|
UpgradeTaskPageResponse page = service.listTasks(1, 10, "", "", "2026-04-16");
|
||||||
|
|
||||||
|
Assertions.assertEquals(1L, page.getTotal());
|
||||||
|
Assertions.assertEquals(1, page.getItems().size());
|
||||||
|
Assertions.assertEquals("UPG-001", page.getItems().get(0).getTaskId());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldReturnUpgradeTaskDetail() {
|
void shouldReturnUpgradeTaskDetail() {
|
||||||
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
InMemoryUpgradeTaskRepository repository = new InMemoryUpgradeTaskRepository();
|
||||||
@@ -214,10 +278,21 @@ class UpgradeServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UpgradeTaskEntity> findPage(String taskType, String status, int offset, int limit) {
|
public List<UpgradeTaskEntity> findPage(
|
||||||
|
String taskType,
|
||||||
|
String status,
|
||||||
|
LocalDateTime startedAtBegin,
|
||||||
|
LocalDateTime startedAtEndExclusive,
|
||||||
|
int offset,
|
||||||
|
int limit
|
||||||
|
) {
|
||||||
return store.values().stream()
|
return store.values().stream()
|
||||||
.filter(entity -> taskType == null || taskType.isBlank() || taskType.equals(entity.getTaskType()))
|
.filter(entity -> taskType == null || taskType.isBlank() || taskType.equals(entity.getTaskType()))
|
||||||
.filter(entity -> status == null || status.isBlank() || status.equals(entity.getStatus()))
|
.filter(entity -> status == null || status.isBlank() || status.equals(entity.getStatus()))
|
||||||
|
.filter(entity -> startedAtBegin == null
|
||||||
|
|| (entity.getStartedAt() != null && !entity.getStartedAt().isBefore(startedAtBegin)))
|
||||||
|
.filter(entity -> startedAtEndExclusive == null
|
||||||
|
|| (entity.getStartedAt() != null && entity.getStartedAt().isBefore(startedAtEndExclusive)))
|
||||||
.sorted(Comparator.comparing(UpgradeTaskEntity::getTaskId).reversed())
|
.sorted(Comparator.comparing(UpgradeTaskEntity::getTaskId).reversed())
|
||||||
.skip(offset)
|
.skip(offset)
|
||||||
.limit(limit)
|
.limit(limit)
|
||||||
@@ -225,8 +300,8 @@ class UpgradeServiceTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long countPage(String taskType, String status) {
|
public long countPage(String taskType, String status, LocalDateTime startedAtBegin, LocalDateTime startedAtEndExclusive) {
|
||||||
return findPage(taskType, status, 0, Integer.MAX_VALUE).size();
|
return findPage(taskType, status, startedAtBegin, startedAtEndExclusive, 0, Integer.MAX_VALUE).size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user