Pulse/internal/mock/config_validation.go
2026-04-11 13:50:38 +01:00

153 lines
3.8 KiB
Go

package mock
import (
"math"
"strings"
"time"
"unicode"
)
const (
minMockNodeCount = 1
maxMockNodeCount = 64
maxMockVMsPerNode = 128
maxMockLXCsPerNode = 128
maxMockDockerHostCount = 64
maxMockDockerContainersPerHost = 256
maxMockGenericHostCount = 256
maxMockK8sClusterCount = 32
maxMockK8sNodesPerCluster = 128
maxMockK8sPodsPerCluster = 1000
maxMockK8sDeploymentsPerCluster = 256
maxMockHighLoadNodes = 256
maxMockHighLoadNodeChars = 128
minMockUpdateInterval = time.Second
maxMockUpdateInterval = 5 * time.Minute
)
func normalizeMockConfig(cfg MockConfig) MockConfig {
cfg.NodeCount = clampInt(cfg.NodeCount, minMockNodeCount, maxMockNodeCount)
cfg.VMsPerNode = clampInt(cfg.VMsPerNode, 0, maxMockVMsPerNode)
cfg.LXCsPerNode = clampInt(cfg.LXCsPerNode, 0, maxMockLXCsPerNode)
cfg.DockerHostCount = clampInt(cfg.DockerHostCount, 0, maxMockDockerHostCount)
cfg.DockerContainersPerHost = clampInt(cfg.DockerContainersPerHost, 0, maxMockDockerContainersPerHost)
cfg.GenericHostCount = clampInt(cfg.GenericHostCount, 0, maxMockGenericHostCount)
cfg.K8sClusterCount = clampInt(cfg.K8sClusterCount, 0, maxMockK8sClusterCount)
cfg.K8sNodesPerCluster = clampInt(cfg.K8sNodesPerCluster, 0, maxMockK8sNodesPerCluster)
cfg.K8sPodsPerCluster = clampInt(cfg.K8sPodsPerCluster, 0, maxMockK8sPodsPerCluster)
cfg.K8sDeploymentsPerCluster = clampInt(cfg.K8sDeploymentsPerCluster, 0, maxMockK8sDeploymentsPerCluster)
cfg.StoppedPercent = normalizeStoppedPercent(cfg.StoppedPercent)
cfg.UpdateInterval = normalizeMockUpdateInterval(cfg.UpdateInterval)
cfg.HighLoadNodes = normalizeHighLoadNodes(cfg.HighLoadNodes)
return cfg
}
func mockConfigsEqual(a, b MockConfig) bool {
if a.NodeCount != b.NodeCount ||
a.VMsPerNode != b.VMsPerNode ||
a.LXCsPerNode != b.LXCsPerNode ||
a.DockerHostCount != b.DockerHostCount ||
a.DockerContainersPerHost != b.DockerContainersPerHost ||
a.GenericHostCount != b.GenericHostCount ||
a.K8sClusterCount != b.K8sClusterCount ||
a.K8sNodesPerCluster != b.K8sNodesPerCluster ||
a.K8sPodsPerCluster != b.K8sPodsPerCluster ||
a.K8sDeploymentsPerCluster != b.K8sDeploymentsPerCluster ||
a.RandomMetrics != b.RandomMetrics ||
a.StoppedPercent != b.StoppedPercent ||
a.UpdateInterval != b.UpdateInterval {
return false
}
if len(a.HighLoadNodes) != len(b.HighLoadNodes) {
return false
}
for i := range a.HighLoadNodes {
if a.HighLoadNodes[i] != b.HighLoadNodes[i] {
return false
}
}
return true
}
func normalizeStoppedPercent(v float64) float64 {
if math.IsNaN(v) || math.IsInf(v, 0) {
return DefaultConfig.StoppedPercent
}
if v < 0 {
return 0
}
if v > 1 {
return 1
}
return v
}
func normalizeMockUpdateInterval(v time.Duration) time.Duration {
if v <= 0 {
return DefaultConfig.UpdateInterval
}
if v < minMockUpdateInterval {
return minMockUpdateInterval
}
if v > maxMockUpdateInterval {
return maxMockUpdateInterval
}
return v
}
func normalizeHighLoadNodes(nodes []string) []string {
if len(nodes) == 0 {
return nil
}
limit := len(nodes)
if limit > maxMockHighLoadNodes {
limit = maxMockHighLoadNodes
}
out := make([]string, 0, limit)
seen := make(map[string]struct{}, limit)
for _, raw := range nodes {
if len(out) >= maxMockHighLoadNodes {
break
}
name := strings.TrimSpace(raw)
if name == "" || len(name) > maxMockHighLoadNodeChars || containsControlChars(name) {
continue
}
if _, exists := seen[name]; exists {
continue
}
seen[name] = struct{}{}
out = append(out, name)
}
if len(out) == 0 {
return nil
}
return out
}
func containsControlChars(s string) bool {
for _, r := range s {
if unicode.IsControl(r) {
return true
}
}
return false
}
func clampInt(v, min, max int) int {
if v < min {
return min
}
if v > max {
return max
}
return v
}