升级任务
This commit is contained in:
parent
57639e78a1
commit
2f81beb0d8
@ -1,6 +1,10 @@
|
|||||||
spring:
|
spring:
|
||||||
application:
|
application:
|
||||||
name: tms-framework
|
name: tms-framework
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
max-file-size: 104857600
|
||||||
|
max-request-size: 104857600
|
||||||
|
|
||||||
server:
|
server:
|
||||||
port: 8080
|
port: 8080
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import org.springframework.validation.FieldError;
|
|||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||||
|
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||||
|
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class GlobalExceptionHandler {
|
public class GlobalExceptionHandler {
|
||||||
@ -45,6 +46,12 @@ public class GlobalExceptionHandler {
|
|||||||
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI());
|
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), ex.getMessage()).withPath(request.getRequestURI());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(MaxUploadSizeExceededException.class)
|
||||||
|
public ApiResponse<Void> handleMaxUploadSizeExceeded(MaxUploadSizeExceededException ex, HttpServletRequest request) {
|
||||||
|
return ApiResponse.fail(ErrorCode.VALIDATE_FAILED.getCode(), "upload file size exceeds limit")
|
||||||
|
.withPath(request.getRequestURI());
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(PcieCryptoException.class)
|
@ExceptionHandler(PcieCryptoException.class)
|
||||||
public ApiResponse<Void> handleCryptoCardException(PcieCryptoException ex, HttpServletRequest request) {
|
public ApiResponse<Void> handleCryptoCardException(PcieCryptoException ex, HttpServletRequest request) {
|
||||||
return ApiResponse.fail(ErrorCode.CRYPTO_CARD_ERROR.getCode(), ex.getMessage())
|
return ApiResponse.fail(ErrorCode.CRYPTO_CARD_ERROR.getCode(), ex.getMessage())
|
||||||
|
|||||||
@ -15,6 +15,7 @@ import io.swagger.v3.oas.annotations.Operation;
|
|||||||
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.Parameter;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
@ -26,17 +27,13 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/api/v1")
|
@RequestMapping("/api/v1")
|
||||||
|
@RequiredArgsConstructor
|
||||||
@Tag(name = "离线升级管理", description = "离线升级包上传、预检、任务创建、执行和升级记录查询接口")
|
@Tag(name = "离线升级管理", description = "离线升级包上传、预检、任务创建、执行和升级记录查询接口")
|
||||||
public class UpgradeController {
|
public class UpgradeController {
|
||||||
|
|
||||||
private final UpgradeService upgradeService;
|
private final UpgradeService upgradeService;
|
||||||
private final FileService fileService;
|
private final FileService fileService;
|
||||||
|
|
||||||
public UpgradeController(UpgradeService upgradeService, FileService fileService) {
|
|
||||||
this.upgradeService = upgradeService;
|
|
||||||
this.fileService = fileService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/upgrade-packages")
|
@PostMapping("/upgrade-packages")
|
||||||
@Operation(summary = "上传离线升级包", description = "上传离线升级包,返回 fileId 供升级预检和任务创建使用。")
|
@Operation(summary = "上传离线升级包", description = "上传离线升级包,返回 fileId 供升级预检和任务创建使用。")
|
||||||
public ApiResponse<FileUploadResponse> uploadPackage(
|
public ApiResponse<FileUploadResponse> uploadPackage(
|
||||||
|
|||||||
@ -98,8 +98,9 @@ public class UpgradeTaskRunner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DeviceSoftwareVersionEntity versionEntity = new DeviceSoftwareVersionEntity();
|
DeviceSoftwareVersionEntity versionEntity = new DeviceSoftwareVersionEntity();
|
||||||
versionEntity.setComponentCode(task.getTaskType());
|
String componentCode = componentCode(task.getTaskType());
|
||||||
versionEntity.setComponentName(componentName(task.getTaskType()));
|
versionEntity.setComponentCode(componentCode);
|
||||||
|
versionEntity.setComponentName(componentName(componentCode));
|
||||||
versionEntity.setCurrentVersion(task.getTargetVersion());
|
versionEntity.setCurrentVersion(task.getTargetVersion());
|
||||||
versionEntity.setSourceType("UPGRADE");
|
versionEntity.setSourceType("UPGRADE");
|
||||||
versionEntity.setDetectedAt(LocalDateTime.now());
|
versionEntity.setDetectedAt(LocalDateTime.now());
|
||||||
@ -211,12 +212,18 @@ public class UpgradeTaskRunner {
|
|||||||
private String componentName(String componentCode) {
|
private String componentName(String componentCode) {
|
||||||
return switch (trim(componentCode)) {
|
return switch (trim(componentCode)) {
|
||||||
case "TMS" -> "设备管理软件";
|
case "TMS" -> "设备管理软件";
|
||||||
case "RECEIVER" -> "标准收发器";
|
case "APP" -> "标准收发器";
|
||||||
case "FIRMWARE" -> "固件";
|
|
||||||
default -> componentCode;
|
default -> componentCode;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String componentCode(String taskType) {
|
||||||
|
return switch (trim(taskType)) {
|
||||||
|
case "RECEIVER" -> "APP";
|
||||||
|
default -> trim(taskType);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
private String trim(String value) {
|
private String trim(String value) {
|
||||||
return value == null ? "" : value.trim();
|
return value == null ? "" : value.trim();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,11 @@ spring:
|
|||||||
application:
|
application:
|
||||||
# Spring 应用名;用于日志、注册中心标识等。
|
# Spring 应用名;用于日志、注册中心标识等。
|
||||||
name: tms-framework
|
name: tms-framework
|
||||||
|
servlet:
|
||||||
|
multipart:
|
||||||
|
# Spring/Tomcat multipart 解析上限;必须不小于业务上传上限,否则请求会在进入 Controller 前被拒绝。
|
||||||
|
max-file-size: ${TMS_FILE_STORAGE_MAX_FILE_SIZE_BYTES:104857600}
|
||||||
|
max-request-size: ${TMS_FILE_STORAGE_MAX_FILE_SIZE_BYTES:104857600}
|
||||||
profiles:
|
profiles:
|
||||||
# 默认激活环境;可通过 --spring.profiles.active=prod 覆盖。
|
# 默认激活环境;可通过 --spring.profiles.active=prod 覆盖。
|
||||||
active: dev
|
active: dev
|
||||||
@ -173,7 +178,7 @@ tms:
|
|||||||
# 升级任务统一日志目录。
|
# 升级任务统一日志目录。
|
||||||
log-dir: ${TMS_UPGRADE_LOG_DIR:/home/tms/tmp/tms-upgrade-logs}
|
log-dir: ${TMS_UPGRADE_LOG_DIR:/home/tms/tmp/tms-upgrade-logs}
|
||||||
# 升级包验签使用的公钥 PEM 文件路径;为空时升级预检会拒绝通过。
|
# 升级包验签使用的公钥 PEM 文件路径;为空时升级预检会拒绝通过。
|
||||||
signature-public-key-pem-path: ${TMS_UPGRADE_SIGNATURE_PUBLIC_KEY_PEM_PATH:}
|
signature-public-key-pem-path: ${TMS_UPGRADE_SIGNATURE_PUBLIC_KEY_PEM_PATH:/home/tms/cert/public_key.pem}
|
||||||
mk:
|
mk:
|
||||||
init-identify:
|
init-identify:
|
||||||
# SDFE_InitIdentify 旧 PIN(Base64 编码);主密钥初始化接口会读取该值。
|
# SDFE_InitIdentify 旧 PIN(Base64 编码);主密钥初始化接口会读取该值。
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
package com.cisd.tms.common.exception;
|
||||||
|
|
||||||
|
import com.cisd.tms.common.api.ApiResponse;
|
||||||
|
import com.cisd.tms.common.enums.ErrorCode;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.mock.web.MockHttpServletRequest;
|
||||||
|
import org.springframework.web.multipart.MaxUploadSizeExceededException;
|
||||||
|
|
||||||
|
class GlobalExceptionHandlerTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldHandleMultipartMaxUploadSizeExceededAsValidationFailure() {
|
||||||
|
GlobalExceptionHandler handler = new GlobalExceptionHandler();
|
||||||
|
MockHttpServletRequest request = new MockHttpServletRequest("POST", "/api/v1/upgrade-packages");
|
||||||
|
|
||||||
|
ApiResponse<Void> response = handler.handleMaxUploadSizeExceeded(
|
||||||
|
new MaxUploadSizeExceededException(104857600),
|
||||||
|
request
|
||||||
|
);
|
||||||
|
|
||||||
|
Assertions.assertFalse(response.isSuccess());
|
||||||
|
Assertions.assertEquals(ErrorCode.VALIDATE_FAILED.getCode(), response.getCode());
|
||||||
|
Assertions.assertEquals("upload file size exceeds limit", response.getMsg());
|
||||||
|
Assertions.assertEquals("/api/v1/upgrade-packages", response.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,32 @@
|
|||||||
|
package com.cisd.tms.config;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.List;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.env.YamlPropertySourceLoader;
|
||||||
|
import org.springframework.core.env.PropertySource;
|
||||||
|
import org.springframework.core.io.FileSystemResource;
|
||||||
|
|
||||||
|
class MultipartUploadConfigurationTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldConfigureSpringMultipartLimitsForLargeUpgradePackages() throws Exception {
|
||||||
|
FileSystemResource resource = new FileSystemResource(Path.of("src/main/resources/application.yml"));
|
||||||
|
List<PropertySource<?>> propertySources = new YamlPropertySourceLoader().load("application", resource);
|
||||||
|
|
||||||
|
Object maxFileSize = findProperty(propertySources, "spring.servlet.multipart.max-file-size");
|
||||||
|
Object maxRequestSize = findProperty(propertySources, "spring.servlet.multipart.max-request-size");
|
||||||
|
|
||||||
|
Assertions.assertEquals("${TMS_FILE_STORAGE_MAX_FILE_SIZE_BYTES:104857600}", maxFileSize);
|
||||||
|
Assertions.assertEquals("${TMS_FILE_STORAGE_MAX_FILE_SIZE_BYTES:104857600}", maxRequestSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object findProperty(List<PropertySource<?>> propertySources, String name) {
|
||||||
|
return propertySources.stream()
|
||||||
|
.filter(source -> source.containsProperty(name))
|
||||||
|
.findFirst()
|
||||||
|
.map(source -> source.getProperty(name))
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -56,6 +56,32 @@ class UpgradeTaskRunnerTest {
|
|||||||
Assertions.assertTrue(log.indexOf("execute") < log.indexOf("verify"));
|
Assertions.assertTrue(log.indexOf("execute") < log.indexOf("verify"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldUpdateAppSoftwareVersionWhenReceiverUpgradeSucceeds() throws Exception {
|
||||||
|
Path tempDir = Files.createTempDirectory("upgrade-runner-test");
|
||||||
|
FileRecordEntity fileRecord = buildPackage(tempDir, false, "#!/bin/sh\necho execute\nexit 0\n", false);
|
||||||
|
InMemoryFileRecordRepository fileRepository = new InMemoryFileRecordRepository();
|
||||||
|
fileRepository.save(fileRecord);
|
||||||
|
InMemoryUpgradeTaskRepository taskRepository = new InMemoryUpgradeTaskRepository();
|
||||||
|
InMemoryDeviceSoftwareVersionRepository versionRepository = new InMemoryDeviceSoftwareVersionRepository();
|
||||||
|
|
||||||
|
UpgradeTaskRunner runner = new UpgradeTaskRunner(
|
||||||
|
taskRepository,
|
||||||
|
fileRepository,
|
||||||
|
versionRepository,
|
||||||
|
stagingService(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||||
|
properties(tempDir.resolve("staging"), tempDir.resolve("logs")),
|
||||||
|
objectMapper
|
||||||
|
);
|
||||||
|
|
||||||
|
runner.run(task("UPG-001-R", fileRecord.getFileId(), "RECEIVER", "V1.4.0"));
|
||||||
|
|
||||||
|
Assertions.assertEquals("SUCCESS", taskRepository.status);
|
||||||
|
Assertions.assertNull(versionRepository.store.get("RECEIVER"));
|
||||||
|
Assertions.assertEquals("V1.4.0", versionRepository.store.get("APP").getCurrentVersion());
|
||||||
|
Assertions.assertEquals("标准收发器", versionRepository.store.get("APP").getComponentName());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldMarkTaskFailedWhenExecuteScriptFails() throws Exception {
|
void shouldMarkTaskFailedWhenExecuteScriptFails() throws Exception {
|
||||||
Path tempDir = Files.createTempDirectory("upgrade-runner-test");
|
Path tempDir = Files.createTempDirectory("upgrade-runner-test");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user