refactor config and nginx parsers
This commit is contained in:
@@ -175,3 +175,14 @@
|
||||
|
||||
- native 自动修复未实现(JAR 链接漂移修复需 filestore identity + release 校验)。
|
||||
- `coverage.out` 未重新生成(不含新包)。
|
||||
|
||||
---
|
||||
|
||||
## 2026-08-22 Sonar 复杂度继续收敛
|
||||
|
||||
- 将部署配置的精确键校验拆为 root、daemon、backend、Node SSR 及槽位校验函数,保留原有字段与错误语义。
|
||||
- 将 backend 校验按 native/container 分支拆分,降低单方法认知复杂度。
|
||||
- 将 Node SSR Nginx marker 定位与 server 收集拆分,保留重复 marker、重复端口和槽位数量校验。
|
||||
- 将容器镜像解析的平台校验、tag 校验、仓库 digest 收集拆分,保留摘要唯一性要求。
|
||||
|
||||
验证:`GOCACHE=/tmp/yms-go-cache go test ./...` 通过。
|
||||
|
||||
@@ -212,16 +212,31 @@ func validateExactDocumentKeys(document []byte) error {
|
||||
if err := toml.Unmarshal(document, &root); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(root, "", "daemon", "backend", "nodeSsr"); err != nil {
|
||||
if err := validateRootKeys(root); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateDaemonKeys(root); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := validateBackendKeys(root); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateOptionalNodeSsrKeys(root)
|
||||
}
|
||||
|
||||
func validateRootKeys(root map[string]any) error {
|
||||
return rejectUnknownKeys(root, "", "daemon", "backend", "nodeSsr")
|
||||
}
|
||||
|
||||
func validateDaemonKeys(root map[string]any) error {
|
||||
daemon, err := exactTable(root, "", "daemon")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(daemon, "daemon", "environment"); err != nil {
|
||||
return err
|
||||
}
|
||||
return rejectUnknownKeys(daemon, "daemon", "environment")
|
||||
}
|
||||
|
||||
func validateBackendKeys(root map[string]any) error {
|
||||
backend, err := exactTable(root, "", "backend")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -233,18 +248,10 @@ func validateExactDocumentKeys(document []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(slots, "backend.slot", "8080", "8081"); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, port := range []string{"8080", "8081"} {
|
||||
slot, err := exactTable(slots, "backend.slot", port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(slot, "backend.slot."+port, "unit", "jar", "container_name", "health_endpoint"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return validateSlotKeys(slots, "backend.slot", []string{"8080", "8081"}, []string{"unit", "jar", "container_name", "health_endpoint"})
|
||||
}
|
||||
|
||||
func validateOptionalNodeSsrKeys(root map[string]any) error {
|
||||
nodeSsrValue, found := root["nodeSsr"]
|
||||
if !found {
|
||||
return nil
|
||||
@@ -263,15 +270,19 @@ func validateExactDocumentKeys(document []byte) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(nodeSlots, "nodeSsr.slot", "18910", "28910"); err != nil {
|
||||
return validateSlotKeys(nodeSlots, "nodeSsr.slot", []string{"18910", "28910"}, []string{"container_name", "health_endpoint"})
|
||||
}
|
||||
|
||||
func validateSlotKeys(slots map[string]any, parent string, ports []string, allowed []string) error {
|
||||
if err := rejectUnknownKeys(slots, parent, ports...); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, port := range []string{"18910", "28910"} {
|
||||
slot, err := exactTable(nodeSlots, "nodeSsr.slot", port)
|
||||
for _, port := range ports {
|
||||
slot, err := exactTable(slots, parent, port)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := rejectUnknownKeys(slot, "nodeSsr.slot."+port, "container_name", "health_endpoint"); err != nil {
|
||||
if err := rejectUnknownKeys(slot, parent+"."+port, allowed...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -343,33 +354,41 @@ func validateBackend(backend Backend) error {
|
||||
}
|
||||
switch backend.Type {
|
||||
case BackendTypeNative:
|
||||
if backend.Slot.Port8080.ContainerName != "" || backend.Slot.Port8081.ContainerName != "" {
|
||||
return errors.New("native backend slots do not accept container_name")
|
||||
}
|
||||
if backend.ReleaseDir != nativeReleaseDir {
|
||||
return fmt.Errorf("backend.release_dir must be %q", nativeReleaseDir)
|
||||
}
|
||||
if backend.ActiveJAR != nativeActiveJAR {
|
||||
return fmt.Errorf("backend.active_jar must be %q", nativeActiveJAR)
|
||||
}
|
||||
return validateNativeBackendSlots(backend.Slot)
|
||||
return validateNativeBackend(backend)
|
||||
case BackendTypeContainer:
|
||||
if backend.ReleaseDir != "" || backend.ActiveJAR != "" {
|
||||
return errors.New("container backend does not accept release_dir or active_jar")
|
||||
}
|
||||
if backend.Slot.Port8080.Unit != "" || backend.Slot.Port8080.JAR != "" || backend.Slot.Port8081.Unit != "" || backend.Slot.Port8081.JAR != "" {
|
||||
return errors.New("container backend slots do not accept unit or jar")
|
||||
}
|
||||
if err := validateContainerSlot("backend.slot.8080", backend.Slot.Port8080, containerName8080, nativeHealthURL8080); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateContainerSlot("backend.slot.8081", backend.Slot.Port8081, containerName8081, nativeHealthURL8081)
|
||||
return validateContainerBackend(backend)
|
||||
default:
|
||||
return fmt.Errorf("backend.type must be %q or %q", BackendTypeNative, BackendTypeContainer)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func validateNativeBackend(backend Backend) error {
|
||||
if backend.Slot.Port8080.ContainerName != "" || backend.Slot.Port8081.ContainerName != "" {
|
||||
return errors.New("native backend slots do not accept container_name")
|
||||
}
|
||||
if backend.ReleaseDir != nativeReleaseDir {
|
||||
return fmt.Errorf("backend.release_dir must be %q", nativeReleaseDir)
|
||||
}
|
||||
if backend.ActiveJAR != nativeActiveJAR {
|
||||
return fmt.Errorf("backend.active_jar must be %q", nativeActiveJAR)
|
||||
}
|
||||
return validateNativeBackendSlots(backend.Slot)
|
||||
}
|
||||
|
||||
func validateContainerBackend(backend Backend) error {
|
||||
if backend.ReleaseDir != "" || backend.ActiveJAR != "" {
|
||||
return errors.New("container backend does not accept release_dir or active_jar")
|
||||
}
|
||||
if backend.Slot.Port8080.Unit != "" || backend.Slot.Port8080.JAR != "" || backend.Slot.Port8081.Unit != "" || backend.Slot.Port8081.JAR != "" {
|
||||
return errors.New("container backend slots do not accept unit or jar")
|
||||
}
|
||||
if err := validateContainerSlot("backend.slot.8080", backend.Slot.Port8080, containerName8080, nativeHealthURL8080); err != nil {
|
||||
return err
|
||||
}
|
||||
return validateContainerSlot("backend.slot.8081", backend.Slot.Port8081, containerName8081, nativeHealthURL8081)
|
||||
}
|
||||
|
||||
func validateNativeBackendSlots(slots BackendSlots) error {
|
||||
if err := validateNativeSlot("backend.slot.8080", slots.Port8080, nativeUnit8080, nativeSlotJAR8080, nativeHealthURL8080); err != nil {
|
||||
return err
|
||||
|
||||
@@ -78,44 +78,60 @@ func parseNodeSsrBlock(content []byte) (nodeSsrBlock, error) {
|
||||
return nodeSsrBlock{}, errors.New("host Nginx configuration is empty")
|
||||
}
|
||||
lines := strings.Split(string(content), "\n")
|
||||
begin, end, err := findNodeSsrMarkers(lines)
|
||||
if err != nil {
|
||||
return nodeSsrBlock{}, err
|
||||
}
|
||||
servers, err := collectNodeSsrServers(lines, begin, end)
|
||||
if err != nil {
|
||||
return nodeSsrBlock{}, err
|
||||
}
|
||||
return nodeSsrBlock{lines: lines, servers: servers}, nil
|
||||
}
|
||||
|
||||
func findNodeSsrMarkers(lines []string) (int, int, error) {
|
||||
begin, end := -1, -1
|
||||
for index, line := range lines {
|
||||
switch strings.TrimSpace(line) {
|
||||
case nodeSsrManagedBegin:
|
||||
if begin != -1 {
|
||||
return nodeSsrBlock{}, errors.New("host Nginx configuration contains duplicate Node SSR upstream begin markers")
|
||||
return 0, 0, errors.New("host Nginx configuration contains duplicate Node SSR upstream begin markers")
|
||||
}
|
||||
begin = index
|
||||
case nodeSsrManagedEnd:
|
||||
if end != -1 {
|
||||
return nodeSsrBlock{}, errors.New("host Nginx configuration contains duplicate Node SSR upstream end markers")
|
||||
return 0, 0, errors.New("host Nginx configuration contains duplicate Node SSR upstream end markers")
|
||||
}
|
||||
end = index
|
||||
}
|
||||
}
|
||||
if begin == -1 || end <= begin {
|
||||
return nodeSsrBlock{}, errors.New("host Nginx configuration requires one ordered Node SSR upstream marker pair")
|
||||
return 0, 0, errors.New("host Nginx configuration requires one ordered Node SSR upstream marker pair")
|
||||
}
|
||||
return begin, end, nil
|
||||
}
|
||||
|
||||
func collectNodeSsrServers(lines []string, begin, end int) ([]nodeSsrServer, error) {
|
||||
servers := make([]nodeSsrServer, 0, 2)
|
||||
seen := make(map[int]struct{}, 2)
|
||||
for index := begin + 1; index < end; index++ {
|
||||
server, found, err := parseNodeSsrServer(lines[index], index)
|
||||
if err != nil {
|
||||
return nodeSsrBlock{}, err
|
||||
return nil, err
|
||||
}
|
||||
if !found {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[server.port]; exists {
|
||||
return nodeSsrBlock{}, fmt.Errorf("managed Node SSR upstream contains duplicate port %d", server.port)
|
||||
return nil, fmt.Errorf("managed Node SSR upstream contains duplicate port %d", server.port)
|
||||
}
|
||||
seen[server.port] = struct{}{}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
if len(servers) != 2 {
|
||||
return nodeSsrBlock{}, fmt.Errorf("managed Node SSR upstream must contain exactly two servers, got %d", len(servers))
|
||||
return nil, fmt.Errorf("managed Node SSR upstream must contain exactly two servers, got %d", len(servers))
|
||||
}
|
||||
return nodeSsrBlock{lines: lines, servers: servers}, nil
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
// parseNodeSsrServer parses one server line inside the managed Node SSR block.
|
||||
|
||||
Reference in New Issue
Block a user