88 lines
2.5 KiB
Go
88 lines
2.5 KiB
Go
package app
|
|
|
|
import (
|
|
"net/http"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------
|
|
// traffic audit (sanity checks / duplicates / nft consistency)
|
|
// ---------------------------------------------------------------------
|
|
//
|
|
// EN: Provides a pragmatic sanity-check endpoint for troubleshooting.
|
|
// EN: We check:
|
|
// EN: - traffic mode health (evaluateTrafficMode)
|
|
// EN: - runtime marks duplicates (target+app_key)
|
|
// EN: - nft chain consistency (state <-> output_apps rules)
|
|
// RU: Практичный sanity-check эндпоинт для диагностики.
|
|
// RU: Проверяем:
|
|
// RU: - health traffic mode (evaluateTrafficMode)
|
|
// RU: - дубли runtime marks (target+app_key)
|
|
// RU: - консистентность nft chain (state <-> output_apps rules)
|
|
|
|
func handleTrafficAudit(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet {
|
|
http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
|
|
now := time.Now().UTC().Format(time.RFC3339)
|
|
|
|
// 1) Traffic mode status (includes route probe).
|
|
traffic := evaluateTrafficMode(loadTrafficModeState())
|
|
|
|
// 2) Profiles (persistent) duplicates by (target, app_key).
|
|
profiles := listTrafficAppProfiles()
|
|
profDups := findProfileDuplicates(profiles)
|
|
|
|
// 3) Runtime marks state + duplicates.
|
|
_ = pruneExpiredAppMarks()
|
|
appMarksMu.Lock()
|
|
marksSt := loadAppMarksState()
|
|
appMarksMu.Unlock()
|
|
|
|
markDups := findMarkDuplicates(marksSt.Items)
|
|
|
|
// 4) nft output_apps rules check (state <-> nft).
|
|
nftIssues, nftSummary := auditNftAppMarks(marksSt.Items)
|
|
|
|
issues := []string{}
|
|
if !traffic.Healthy {
|
|
issues = append(issues, "traffic_mode_unhealthy: "+strings.TrimSpace(traffic.Message))
|
|
}
|
|
for _, d := range profDups {
|
|
issues = append(issues, "profile_duplicate: "+d)
|
|
}
|
|
for _, d := range markDups {
|
|
issues = append(issues, "mark_duplicate: "+d)
|
|
}
|
|
issues = append(issues, nftIssues...)
|
|
|
|
ok := true
|
|
for _, it := range issues {
|
|
if strings.HasPrefix(it, "traffic_mode_unhealthy:") ||
|
|
strings.HasPrefix(it, "nft_error:") ||
|
|
strings.HasPrefix(it, "nft_missing_rule:") {
|
|
ok = false
|
|
break
|
|
}
|
|
}
|
|
|
|
pretty := buildTrafficAuditPretty(now, traffic, profiles, marksSt.Items, issues, nftSummary)
|
|
|
|
writeJSON(w, http.StatusOK, map[string]any{
|
|
"ok": ok,
|
|
"now": now,
|
|
"message": "ok",
|
|
"pretty": pretty,
|
|
"traffic": traffic,
|
|
"counts": map[string]any{
|
|
"profiles": len(profiles),
|
|
"marks": len(marksSt.Items),
|
|
},
|
|
"issues": issues,
|
|
"nft": nftSummary,
|
|
})
|
|
}
|