mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-10-08 16:46:37 +08:00
[修复] 更新数据库字段类型为text,添加消息截断逻辑以支持更长的消息内容
This commit is contained in:
@@ -254,6 +254,7 @@ func ReportApplyLog(payload ApplyLogPayload) (*model.ApplyLog, error) {
|
||||
payload.Checksum = strings.TrimSpace(payload.Checksum)
|
||||
payload.MainConfigChecksum = strings.TrimSpace(payload.MainConfigChecksum)
|
||||
payload.RouteConfigChecksum = strings.TrimSpace(payload.RouteConfigChecksum)
|
||||
payload.Message = truncateForDatabase(payload.Message, 16000)
|
||||
if payload.NodeID == "" {
|
||||
return nil, errors.New("node_id 不能为空")
|
||||
}
|
||||
@@ -339,6 +340,17 @@ func ListNodeViews() ([]*NodeView, error) {
|
||||
return views, nil
|
||||
}
|
||||
|
||||
func truncateForDatabase(value string, max int) string {
|
||||
if max <= 0 {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(strings.TrimSpace(value))
|
||||
if len(runes) <= max {
|
||||
return string(runes)
|
||||
}
|
||||
return string(runes[:max])
|
||||
}
|
||||
|
||||
const (
|
||||
defaultApplyLogPageSize = 20
|
||||
maxApplyLogPageSize = 200
|
||||
|
||||
@@ -83,10 +83,15 @@ type routeCacheConfig struct {
|
||||
type routeUpstreamConfig struct {
|
||||
Name string
|
||||
Scheme string
|
||||
Addresses []string
|
||||
Servers []routeUpstreamServer
|
||||
UsesNamedUpstream bool
|
||||
}
|
||||
|
||||
type routeUpstreamServer struct {
|
||||
Address string
|
||||
Resolve bool
|
||||
}
|
||||
|
||||
type openRestyConfigSnapshot struct {
|
||||
WorkerProcesses string `json:"worker_processes"`
|
||||
WorkerConnections int `json:"worker_connections"`
|
||||
@@ -671,6 +676,9 @@ func renderRouteConfig(routes []*model.ProxyRoute, cfg openRestyConfigSnapshot)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("路由 %s 上游配置无效", route.Domain)
|
||||
}
|
||||
if err := validateRenderableUpstreams(route.Domain, upstreams, cfg); err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
cacheRules, err := decodeStoredCacheRules(route.CacheRules)
|
||||
if err != nil {
|
||||
return "", nil, fmt.Errorf("路由 %s 缓存规则无效", route.Domain)
|
||||
@@ -852,7 +860,7 @@ func renderHTTPRedirectServer(domain string) string {
|
||||
func renderHTTPSServer(domain string, originURL string, originHost string, certificateID uint, customHeaders []ProxyRouteCustomHeaderInput, cacheConfig routeCacheConfig, upstreamConfig routeUpstreamConfig, cfg openRestyConfigSnapshot) string {
|
||||
certPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateCertFileName(certificateID))
|
||||
keyPath := fmt.Sprintf("%s/%s", nginxCertDirPlaceholder, certificateKeyFileName(certificateID))
|
||||
return fmt.Sprintf("server {\n listen 443 ssl http2 reuseport;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n\n location / {\n%s%s%s }\n}\n\n", domain, certPath, keyPath, renderProxyHeaderBlock(originURL, originHost, customHeaders, upstreamConfig), renderRouteCacheBlock(cacheConfig, cfg), renderProxyPassBlock(originURL, upstreamConfig, cfg))
|
||||
return fmt.Sprintf("server {\n listen 443 ssl;\n http2 on;\n server_name %s;\n ssl_certificate %s;\n ssl_certificate_key %s;\n\n location / {\n%s%s%s }\n}\n\n", domain, certPath, keyPath, renderProxyHeaderBlock(originURL, originHost, customHeaders, upstreamConfig), renderRouteCacheBlock(cacheConfig, cfg), renderProxyPassBlock(originURL, upstreamConfig, cfg))
|
||||
}
|
||||
|
||||
func renderConnectionUpgradeMap() string {
|
||||
@@ -997,23 +1005,27 @@ func buildRouteUpstreamConfig(route *model.ProxyRoute, upstreams []string, cfg o
|
||||
if err != nil || parsed.Host == "" || parsed.Scheme == "" {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
if shouldUseRuntimeResolver(upstreams[0], cfg.Resolvers) {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
if strings.TrimSpace(parsed.EscapedPath()) != "" && strings.TrimSpace(parsed.EscapedPath()) != "/" {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
if parsed.RawQuery != "" {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
server := routeUpstreamServer{Address: parsed.Host}
|
||||
if !isIPAddressHostname(parsed.Hostname()) {
|
||||
if strings.TrimSpace(cfg.Resolvers) == "" {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
server.Resolve = true
|
||||
}
|
||||
return routeUpstreamConfig{
|
||||
Name: buildRouteUpstreamName(route),
|
||||
Scheme: parsed.Scheme,
|
||||
Addresses: []string{parsed.Host},
|
||||
Servers: []routeUpstreamServer{server},
|
||||
UsesNamedUpstream: true,
|
||||
}
|
||||
}
|
||||
addresses := make([]string, 0, len(upstreams))
|
||||
servers := make([]routeUpstreamServer, 0, len(upstreams))
|
||||
var scheme string
|
||||
for _, upstream := range upstreams {
|
||||
parsed, err := url.Parse(strings.TrimSpace(upstream))
|
||||
@@ -1031,12 +1043,16 @@ func buildRouteUpstreamConfig(route *model.ProxyRoute, upstreams []string, cfg o
|
||||
} else if scheme != parsed.Scheme {
|
||||
return routeUpstreamConfig{}
|
||||
}
|
||||
addresses = append(addresses, parsed.Host)
|
||||
server := routeUpstreamServer{Address: parsed.Host}
|
||||
if !isIPAddressHostname(parsed.Hostname()) {
|
||||
server.Resolve = true
|
||||
}
|
||||
servers = append(servers, server)
|
||||
}
|
||||
return routeUpstreamConfig{
|
||||
Name: buildRouteUpstreamName(route),
|
||||
Scheme: scheme,
|
||||
Addresses: addresses,
|
||||
Servers: servers,
|
||||
UsesNamedUpstream: true,
|
||||
}
|
||||
}
|
||||
@@ -1064,13 +1080,40 @@ func buildRouteUpstreamName(route *model.ProxyRoute) string {
|
||||
func renderNamedUpstreamBlock(upstreamConfig routeUpstreamConfig) string {
|
||||
var builder strings.Builder
|
||||
builder.WriteString(fmt.Sprintf("upstream %s {\n", upstreamConfig.Name))
|
||||
for _, address := range upstreamConfig.Addresses {
|
||||
builder.WriteString(fmt.Sprintf(" server %s max_fails=3 fail_timeout=10s;\n", address))
|
||||
for _, server := range upstreamConfig.Servers {
|
||||
if server.Resolve {
|
||||
builder.WriteString(fmt.Sprintf(" server %s resolve max_fails=3 fail_timeout=10s;\n", server.Address))
|
||||
continue
|
||||
}
|
||||
builder.WriteString(fmt.Sprintf(" server %s max_fails=3 fail_timeout=10s;\n", server.Address))
|
||||
}
|
||||
builder.WriteString(" keepalive 128;\n}\n\n")
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
func validateRenderableUpstreams(domain string, upstreams []string, cfg openRestyConfigSnapshot) error {
|
||||
if len(upstreams) <= 1 {
|
||||
return nil
|
||||
}
|
||||
if strings.TrimSpace(cfg.Resolvers) != "" {
|
||||
return nil
|
||||
}
|
||||
for _, upstream := range upstreams {
|
||||
parsed, err := url.Parse(strings.TrimSpace(upstream))
|
||||
if err != nil || parsed.Hostname() == "" {
|
||||
return fmt.Errorf("路由 %s 上游配置无效", domain)
|
||||
}
|
||||
if !isIPAddressHostname(parsed.Hostname()) {
|
||||
return fmt.Errorf("路由 %s 的多上游主机名需要先配置 OpenRestyResolvers", domain)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isIPAddressHostname(host string) bool {
|
||||
return net.ParseIP(strings.TrimSpace(host)) != nil
|
||||
}
|
||||
|
||||
func shouldUseRuntimeResolver(originURL string, resolvers string) bool {
|
||||
if strings.TrimSpace(resolvers) == "" {
|
||||
return false
|
||||
|
||||
@@ -81,8 +81,11 @@ func TestCreateTLSCertificateAndRenderHTTPSConfig(t *testing.T) {
|
||||
if strings.Contains(result.Version.MainConfig, "allow 127.0.0.1;") {
|
||||
t.Fatal("expected main config to avoid hard-coded allow rules on observability server")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "listen 443 ssl http2 reuseport;") {
|
||||
t.Fatal("expected rendered config to include https server block with http2 and reuseport enabled")
|
||||
if !strings.Contains(result.Version.RenderedConfig, "listen 443 ssl;") {
|
||||
t.Fatal("expected rendered config to include https ssl listener")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "http2 on;") {
|
||||
t.Fatal("expected rendered config to enable http2 with dedicated directive")
|
||||
}
|
||||
if strings.Contains(result.Version.RenderedConfig, `if ($host != "app.example.com") {`) {
|
||||
t.Fatal("expected rendered config to avoid per-route host guard")
|
||||
@@ -153,14 +156,8 @@ func TestPublishConfigVersionRendersCustomHeaders(t *testing.T) {
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_set_header Connection $connection_upgrade;") {
|
||||
t.Fatal("expected rendered config to use normalized websocket connection header")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "upstream backend_custom_example_com_1 {") {
|
||||
t.Fatal("expected rendered config to define named upstream for simple origins")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "keepalive 128;") {
|
||||
t.Fatal("expected rendered config to enable upstream keepalive")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://backend_custom_example_com_1;") {
|
||||
t.Fatal("expected rendered config to proxy through named upstream when no resolver is required")
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://origin.internal;") {
|
||||
t.Fatal("expected hostname origin without resolver to keep direct proxy_pass")
|
||||
}
|
||||
if strings.Contains(result.Version.RenderedConfig, "proxy_pass $openflare_upstream$request_uri;") {
|
||||
t.Fatal("expected rendered config to avoid runtime-resolved proxy_pass when no resolvers are configured")
|
||||
@@ -242,8 +239,8 @@ func TestPublishConfigVersionRendersRouteLevelCachePolicy(t *testing.T) {
|
||||
if strings.Count(result.Version.RenderedConfig, "proxy_cache openflare_cache;") != 1 {
|
||||
t.Fatal("expected only cache-enabled route to include proxy_cache directive")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://backend_static_example_com_1;") {
|
||||
t.Fatal("expected cache-enabled route to proxy through named upstream")
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://origin.internal;") {
|
||||
t.Fatal("expected cache-enabled hostname route without resolver to keep direct proxy_pass")
|
||||
}
|
||||
if !strings.Contains(result.Version.SnapshotJSON, `"cache_enabled":true`) {
|
||||
t.Fatal("expected snapshot to include route cache toggle")
|
||||
@@ -258,15 +255,15 @@ func TestPublishConfigVersionRendersMultipleUpstreams(t *testing.T) {
|
||||
|
||||
route, err := CreateProxyRoute(ProxyRouteInput{
|
||||
Domain: "lb.example.com",
|
||||
OriginURL: "http://c1:39010",
|
||||
Upstreams: []string{"http://c2:39010", "http://c3:39010"},
|
||||
OriginURL: "http://10.0.0.11:39010",
|
||||
Upstreams: []string{"http://10.0.0.12:39010", "http://10.0.0.13:39010"},
|
||||
Enabled: true,
|
||||
OriginHost: "lb.example.com",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateProxyRoute failed: %v", err)
|
||||
}
|
||||
if !strings.Contains(route.Upstreams, "c2:39010") {
|
||||
if !strings.Contains(route.Upstreams, "10.0.0.12:39010") {
|
||||
t.Fatalf("expected route upstreams to persist, got %s", route.Upstreams)
|
||||
}
|
||||
|
||||
@@ -277,26 +274,45 @@ func TestPublishConfigVersionRendersMultipleUpstreams(t *testing.T) {
|
||||
if !strings.Contains(result.Version.RenderedConfig, "upstream backend_lb_example_com_1 {") {
|
||||
t.Fatal("expected rendered config to define upstream block for load balancing route")
|
||||
}
|
||||
if strings.Count(result.Version.RenderedConfig, "server c") < 3 {
|
||||
if strings.Count(result.Version.RenderedConfig, "max_fails=3 fail_timeout=10s;") < 3 {
|
||||
t.Fatal("expected rendered config to include every upstream server")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server c1:39010 max_fails=3 fail_timeout=10s;") {
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server 10.0.0.11:39010 max_fails=3 fail_timeout=10s;") {
|
||||
t.Fatal("expected rendered config to include primary upstream server")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server c2:39010 max_fails=3 fail_timeout=10s;") {
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server 10.0.0.12:39010 max_fails=3 fail_timeout=10s;") {
|
||||
t.Fatal("expected rendered config to include secondary upstream server")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server c3:39010 max_fails=3 fail_timeout=10s;") {
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server 10.0.0.13:39010 max_fails=3 fail_timeout=10s;") {
|
||||
t.Fatal("expected rendered config to include tertiary upstream server")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass http://backend_lb_example_com_1;") {
|
||||
t.Fatal("expected rendered config to proxy through load balancing upstream")
|
||||
}
|
||||
if !strings.Contains(result.Version.SnapshotJSON, `"upstreams":["http://c1:39010","http://c2:39010","http://c3:39010"]`) {
|
||||
if !strings.Contains(result.Version.SnapshotJSON, `"upstreams":["http://10.0.0.11:39010","http://10.0.0.12:39010","http://10.0.0.13:39010"]`) {
|
||||
t.Fatal("expected snapshot to include upstream list")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishConfigVersionRejectsHostnameLoadBalancingWithoutResolvers(t *testing.T) {
|
||||
setupServiceTestDB(t)
|
||||
|
||||
_, err := CreateProxyRoute(ProxyRouteInput{
|
||||
Domain: "hostname-lb.example.com",
|
||||
OriginURL: "http://c1:39010",
|
||||
Upstreams: []string{"http://c2:39010"},
|
||||
Enabled: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateProxyRoute failed: %v", err)
|
||||
}
|
||||
|
||||
_, err = PublishConfigVersion("root")
|
||||
if err == nil || !strings.Contains(err.Error(), "多上游主机名需要先配置 OpenRestyResolvers") {
|
||||
t.Fatalf("expected hostname load balancing publish validation error, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishConfigVersionOverridesOriginHostHeader(t *testing.T) {
|
||||
setupServiceTestDB(t)
|
||||
|
||||
@@ -323,11 +339,8 @@ func TestPublishConfigVersionOverridesOriginHostHeader(t *testing.T) {
|
||||
if !strings.Contains(result.Version.RenderedConfig, `proxy_ssl_name "git.arctel.net";`) {
|
||||
t.Fatal("expected rendered config to set proxy ssl name from origin host override")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "upstream backend_git_arctel_de_1 {") {
|
||||
t.Fatal("expected rendered config to define named upstream for static hostname origins")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://backend_git_arctel_de_1;") {
|
||||
t.Fatal("expected rendered config to proxy through named upstream for hostname origin when resolvers are blank")
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://git.arctel.net;") {
|
||||
t.Fatal("expected rendered config to keep direct proxy_pass for hostname origin when resolvers are blank")
|
||||
}
|
||||
if !strings.Contains(result.Version.SnapshotJSON, `"origin_host":"git.arctel.net"`) {
|
||||
t.Fatal("expected snapshot to include origin_host override")
|
||||
@@ -342,7 +355,7 @@ func TestPublishConfigVersionUsesRuntimeResolverWhenConfigured(t *testing.T) {
|
||||
|
||||
_, err := CreateProxyRoute(ProxyRouteInput{
|
||||
Domain: "resolver.example.com",
|
||||
OriginURL: "https://origin.internal",
|
||||
OriginURL: "https://origin.internal/api",
|
||||
Enabled: true,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -357,13 +370,46 @@ func TestPublishConfigVersionUsesRuntimeResolverWhenConfigured(t *testing.T) {
|
||||
t.Fatal("expected main config to render configured resolver directive")
|
||||
}
|
||||
if strings.Contains(result.Version.RenderedConfig, "upstream backend_resolver_example_com_1 {") {
|
||||
t.Fatal("expected runtime-resolved origin to avoid named upstream block")
|
||||
t.Fatal("expected hostname origin with base path to avoid named upstream block")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, `set $openflare_upstream "https://origin.internal";`) {
|
||||
t.Fatal("expected rendered config to use runtime upstream variable when resolvers are configured")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass $openflare_upstream$request_uri;") {
|
||||
t.Fatal("expected rendered config to proxy via runtime-resolved upstream variable when resolvers are configured")
|
||||
if !strings.Contains(result.Version.RenderedConfig, `set $openflare_upstream_base_path "/api";`) {
|
||||
t.Fatal("expected rendered config to preserve origin base path for runtime-resolved origin")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass $openflare_upstream$openflare_upstream_base_path$request_uri;") {
|
||||
t.Fatal("expected rendered config to proxy via runtime-resolved upstream variable and base path when resolvers are configured")
|
||||
}
|
||||
}
|
||||
|
||||
func TestPublishConfigVersionUsesNamedUpstreamForHostnameOriginsWhenResolversConfigured(t *testing.T) {
|
||||
setupServiceTestDB(t)
|
||||
if err := model.UpdateOption("OpenRestyResolvers", "1.1.1.1"); err != nil {
|
||||
t.Fatalf("UpdateOption OpenRestyResolvers failed: %v", err)
|
||||
}
|
||||
|
||||
_, err := CreateProxyRoute(ProxyRouteInput{
|
||||
Domain: "resolver-upstream.example.com",
|
||||
OriginURL: "https://origin.internal",
|
||||
Enabled: true,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("CreateProxyRoute failed: %v", err)
|
||||
}
|
||||
|
||||
result, err := PublishConfigVersion("root")
|
||||
if err != nil {
|
||||
t.Fatalf("PublishConfigVersion failed: %v", err)
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "upstream backend_resolver_upstream_example_com_1 {") {
|
||||
t.Fatal("expected rendered config to define named upstream for hostname origin when resolvers are configured")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "server origin.internal resolve max_fails=3 fail_timeout=10s;") {
|
||||
t.Fatal("expected rendered config to mark hostname upstream server as resolve")
|
||||
}
|
||||
if !strings.Contains(result.Version.RenderedConfig, "proxy_pass https://backend_resolver_upstream_example_com_1;") {
|
||||
t.Fatal("expected rendered config to proxy through named upstream when resolver-backed hostname upstream is safe")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,6 +442,9 @@ func TestPublishConfigVersionKeepsDirectProxyPassForIPOrigins(t *testing.T) {
|
||||
|
||||
func TestPreviewConfigVersionCanDisableWebsocketHeaders(t *testing.T) {
|
||||
setupServiceTestDB(t)
|
||||
if err := model.UpdateOption("OpenRestyResolvers", ""); err != nil {
|
||||
t.Fatalf("UpdateOption OpenRestyResolvers failed: %v", err)
|
||||
}
|
||||
|
||||
_, err := CreateProxyRoute(ProxyRouteInput{
|
||||
Domain: "ws-off.example.com",
|
||||
|
||||
@@ -418,9 +418,9 @@ func normalizeAgentNodePayload(payload AgentNodePayload) AgentNodePayload {
|
||||
payload.AgentVersion = strings.TrimSpace(payload.AgentVersion)
|
||||
payload.NginxVersion = strings.TrimSpace(payload.NginxVersion)
|
||||
payload.CurrentVersion = strings.TrimSpace(payload.CurrentVersion)
|
||||
payload.LastError = strings.TrimSpace(payload.LastError)
|
||||
payload.LastError = truncateForDatabase(payload.LastError, 16000)
|
||||
payload.OpenrestyStatus = normalizeOpenrestyStatus(payload.OpenrestyStatus)
|
||||
payload.OpenrestyMessage = strings.TrimSpace(payload.OpenrestyMessage)
|
||||
payload.OpenrestyMessage = truncateForDatabase(payload.OpenrestyMessage, 16000)
|
||||
return payload
|
||||
}
|
||||
|
||||
@@ -444,11 +444,11 @@ func applyNodeRuntime(node *model.Node, payload AgentNodePayload, preserveName b
|
||||
node.AgentVersion = strings.TrimSpace(payload.AgentVersion)
|
||||
node.NginxVersion = strings.TrimSpace(payload.NginxVersion)
|
||||
node.OpenrestyStatus = normalizeOpenrestyStatus(payload.OpenrestyStatus)
|
||||
node.OpenrestyMessage = strings.TrimSpace(payload.OpenrestyMessage)
|
||||
node.OpenrestyMessage = truncateForDatabase(payload.OpenrestyMessage, 16000)
|
||||
node.Status = NodeStatusOnline
|
||||
node.CurrentVersion = strings.TrimSpace(payload.CurrentVersion)
|
||||
node.LastSeenAt = time.Now()
|
||||
node.LastError = strings.TrimSpace(payload.LastError)
|
||||
node.LastError = truncateForDatabase(payload.LastError, 16000)
|
||||
if !node.GeoManualOverride {
|
||||
applyGeoInfoFromIP(node, node.IP)
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ func reconcileNodeHealthEvents(tx *gorm.DB, nodeID string, events []AgentNodeHea
|
||||
triggeredAt := timeFromUnix(event.TriggeredAtUnix, reportedAt)
|
||||
if existing, ok := activeByType[eventType]; ok {
|
||||
existing.Severity = event.Severity
|
||||
existing.Message = strings.TrimSpace(event.Message)
|
||||
existing.Message = normalizeHealthEventMessage(event.Message)
|
||||
existing.LastTriggeredAt = triggeredAt
|
||||
existing.ReportedAt = reportedAt
|
||||
existing.RawJSON = marshalJSON(event)
|
||||
@@ -286,7 +286,7 @@ func reconcileNodeHealthEvents(tx *gorm.DB, nodeID string, events []AgentNodeHea
|
||||
EventType: eventType,
|
||||
Severity: event.Severity,
|
||||
Status: NodeHealthEventStatusActive,
|
||||
Message: strings.TrimSpace(event.Message),
|
||||
Message: normalizeHealthEventMessage(event.Message),
|
||||
FirstTriggeredAt: triggeredAt,
|
||||
LastTriggeredAt: triggeredAt,
|
||||
ReportedAt: reportedAt,
|
||||
@@ -330,6 +330,10 @@ func normalizeHealthSeverity(severity string) string {
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeHealthEventMessage(message string) string {
|
||||
return truncateForDatabase(message, 4096)
|
||||
}
|
||||
|
||||
func timeFromUnix(unixSeconds int64, fallback time.Time) time.Time {
|
||||
if unixSeconds <= 0 {
|
||||
return fallback
|
||||
|
||||
Reference in New Issue
Block a user