package redfishprofile import ( "sort" "git.mchus.pro/mchus/logpile/internal/models" ) const ( ModeMatched = "matched" ModeFallback = "fallback" ) func MatchProfiles(signals MatchSignals) MatchResult { type scored struct { profile Profile score int } builtins := BuiltinProfiles() candidates := make([]scored, 0, len(builtins)) allScores := make([]ProfileScore, 0, len(builtins)) for _, profile := range builtins { score := profile.Match(signals) allScores = append(allScores, ProfileScore{ Name: profile.Name(), Score: score, Priority: profile.Priority(), }) if score <= 0 { continue } candidates = append(candidates, scored{profile: profile, score: score}) } sort.Slice(allScores, func(i, j int) bool { if allScores[i].Score == allScores[j].Score { if allScores[i].Priority == allScores[j].Priority { return allScores[i].Name < allScores[j].Name } return allScores[i].Priority < allScores[j].Priority } return allScores[i].Score > allScores[j].Score }) sort.Slice(candidates, func(i, j int) bool { if candidates[i].score == candidates[j].score { return candidates[i].profile.Priority() < candidates[j].profile.Priority() } return candidates[i].score > candidates[j].score }) if len(candidates) == 0 || candidates[0].score < 60 { profiles := make([]Profile, 0, len(builtins)) active := make(map[string]struct{}, len(builtins)) for _, profile := range builtins { if profile.SafeForFallback() { profiles = append(profiles, profile) active[profile.Name()] = struct{}{} } } sortProfiles(profiles) for i := range allScores { _, ok := active[allScores[i].Name] allScores[i].Active = ok } return MatchResult{Mode: ModeFallback, Profiles: profiles, Scores: allScores} } profiles := make([]Profile, 0, len(candidates)) seen := make(map[string]struct{}, len(candidates)) for _, candidate := range candidates { name := candidate.profile.Name() if _, ok := seen[name]; ok { continue } seen[name] = struct{}{} profiles = append(profiles, candidate.profile) } sortProfiles(profiles) for i := range allScores { _, ok := seen[allScores[i].Name] allScores[i].Active = ok } return MatchResult{Mode: ModeMatched, Profiles: profiles, Scores: allScores} } func BuildAcquisitionPlan(signals MatchSignals) AcquisitionPlan { match := MatchProfiles(signals) plan := AcquisitionPlan{Mode: match.Mode} for _, profile := range match.Profiles { plan.Profiles = append(plan.Profiles, profile.Name()) profile.ExtendAcquisitionPlan(&plan, signals) } plan.Profiles = dedupeSorted(plan.Profiles) plan.SeedPaths = dedupeSorted(plan.SeedPaths) plan.CriticalPaths = dedupeSorted(plan.CriticalPaths) plan.PlanBPaths = dedupeSorted(plan.PlanBPaths) plan.Notes = dedupeSorted(plan.Notes) if plan.Mode == ModeFallback { ensureSnapshotMaxDocuments(&plan, 180000) ensurePrefetchEnabled(&plan, true) addPlanNote(&plan, "fallback acquisition expands safe profile probes") } return plan } func ApplyAnalysisProfiles(result *models.AnalysisResult, snapshot map[string]interface{}, signals MatchSignals) MatchResult { match := MatchProfiles(signals) for _, profile := range match.Profiles { profile.PostAnalyze(result, snapshot, signals) } return match } func BuildAnalysisDirectives(match MatchResult) AnalysisDirectives { return ResolveAnalysisPlan(match, nil, DiscoveredResources{}, MatchSignals{}).Directives } func sortProfiles(profiles []Profile) { sort.Slice(profiles, func(i, j int) bool { if profiles[i].Priority() == profiles[j].Priority() { return profiles[i].Name() < profiles[j].Name() } return profiles[i].Priority() < profiles[j].Priority() }) }